Developing a Mobile App for Goods Receiving with Scanner
Goods receiving is the first control point in the supply chain. Actual quantities and SKUs often differ from the order: wrong assortment, shortage, damaged goods, incorrect labeling. A mobile app with scanning support transforms receiving from paper forms into a structured process with immediate verification.
GS1-128 and SSCC Scanning
Items in shipments are marked at multiple levels: unit barcode (EAN-13/EAN-8), box/package barcode (ITF-14, Code 128), SSCC on pallets (Serial Shipping Container Code, 18 digits, Code 128 or GS1-128).
GS1-128 is Code 128 with Application Identifiers (AI): (00) — SSCC, (01) — GTIN, (17) — expiry date YYMMDD, (10) — lot number, (37) — quantity. A single GS1-128 barcode can contain multiple AIs.
class GS1Parser {
private val GROUP_SEPARATOR = '\u001D' // FNC1
fun parse(barcode: String): Map<String, String> {
val result = mutableMapOf<String, String>()
var pos = 0
val raw = barcode.replace("]C1", "").replace("]e0", "") // remove scanner markers
while (pos < raw.length) {
val ai = detectAI(raw, pos) ?: break
pos += ai.length
val value = extractValue(raw, pos, ai)
result[ai] = value
pos += value.length
if (pos < raw.length && raw[pos] == GROUP_SEPARATOR) pos++
}
return result
}
private fun detectAI(s: String, pos: Int): String? {
// AI can be 2, 3, or 4 digits
return listOf(4, 3, 2).firstNotNullOfOrNull { len ->
if (pos + len <= s.length && KNOWN_AIS.contains(s.substring(pos, pos + len)))
s.substring(pos, pos + len) else null
}
}
}
DataMatrix and QR codes in pharmaceuticals and Honest Mark labeling contain similar GS1 data. ML Kit Barcode Scanning decodes them all; the key is correctly parsing Application Identifiers.
PO Verification (Purchase Order)
Basic scenario: load the Purchase Order before receiving, scan incoming goods, compare actual to plan in real-time.
data class ReceivingLine(
val poLineId: String,
val sku: String,
val gtin: String,
val orderedQty: Double,
val receivedQty: Double = 0.0,
val lotNumber: String? = null,
val expiryDate: LocalDate? = null,
val status: LineStatus = LineStatus.PENDING
)
class ReceivingViewModel : ViewModel() {
fun processScan(parsedBarcode: Map<String, String>) {
val gtin = parsedBarcode["01"] ?: parsedBarcode["02"] ?: return
val lot = parsedBarcode["10"]
val expiry = parsedBarcode["17"]?.let { parseExpiry(it) }
val qty = parsedBarcode["37"]?.toDoubleOrNull() ?: 1.0
val line = findLineByGtin(gtin) ?: run {
// Item not in PO — warning, record as unexpected
recordUnexpectedItem(gtin, qty)
return
}
val updated = line.copy(
receivedQty = line.receivedQty + qty,
lotNumber = lot ?: line.lotNumber,
expiryDate = expiry ?: line.expiryDate,
status = when {
line.receivedQty + qty > line.orderedQty * 1.05 -> LineStatus.OVER_RECEIVED
abs(line.receivedQty + qty - line.orderedQty) < 0.01 -> LineStatus.COMPLETED
else -> LineStatus.IN_PROGRESS
}
)
updateLine(updated)
}
}
Over-receiving and under-receiving both require visual warnings. Color coding: green (within tolerance), yellow (minor discrepancy), red (significant over-receipt or defects).
Photo Documentation and Discrepancy Report
Damaged goods require photo documentation. Take photos directly from the app using CameraX (Android) / AVCaptureSession (iOS), linked to the receiving line. Photos upload to S3/MinIO; the report references the image.
Discrepancy Report (TORGA-2 form) is generated automatically from receiving results. PDF via iText on Android or server-side generation via Puppeteer/WeasyPrint. Receiver signature — SignatureView (draw with finger) or DocuSign API integration for legally binding document exchange.
Honest Mark Verification
For goods subject to mandatory marking (milk, water, shoes, clothing, perfume) — verify the marking code via the GIS MT API (Honest Mark): POST /api/v3/true-api/codes/check with DataMatrix code. Response contains code status (in circulation, withdrawn, not found) and product attributes.
Developing a receiving app with GS1-128/DataMatrix scanning, PO verification, and discrepancy reports: 5–7 weeks. With Honest Mark integration, photo documentation, and bidirectional integration with WMS/1C: 10–14 weeks. Pricing is calculated individually.







