Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 62 additions & 5 deletions ios/CodeMatch/Features/History/HistoryScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,8 @@ private struct GroupedMatchDetail: View {
// 納品番号を持たない記録が1件でも混ざるグループは、記録を落とさないよう従来どおり1節にまとめる
let showsDeliveryGroups = !deliveryGroups.isEmpty
&& deliveryGroups.reduce(0) { $0 + $1.entries.count } == group.entries.count
// デンソーは同じ品番の箱がかんばん連番でしか区別できないので、管理コードを添えて見分けやすくする
let showsManagementCodePerBox = group.entries.contains { $0.densoRecord != nil }

List {
Section {
Expand Down Expand Up @@ -416,7 +418,11 @@ private struct GroupedMatchDetail: View {
} else {
Section(AppLocalization.string("各箱の照合記録")) {
ForEach(Array(group.entries.enumerated()), id: \.element.id) { index, entry in
boxEntryRow(entry: entry, number: index + 1)
boxEntryRow(
entry: entry,
number: index + 1,
showsManagementCode: showsManagementCodePerBox
)
}
}
}
Expand All @@ -425,7 +431,7 @@ private struct GroupedMatchDetail: View {
.navigationBarTitleDisplayMode(.inline)
}

/// 1箱分の行。モルテンは同じ納品番号の箱をQRでは区別できないため、管理コードを添える。
/// 1箱分の行。モルテンとデンソーは箱の見分けが付きにくいため、管理コードを添える。
private func boxEntryRow(
entry: MatchHistoryEntry,
number: Int,
Expand Down Expand Up @@ -485,15 +491,17 @@ private struct MatchEntryDetail: View {
.textSelection(.enabled)
}

if let qr = entry.qrPayload.flatMap(KanbanQRRecord.parse) {
// 澤井製作所の解析は寛容でデンソーのQRも受理してしまうため、
// 仕向地ガード付きの `kanbanRecord` から順に分岐する。
if let qr = entry.kanbanRecord {
Section(AppLocalization.string("納品書情報(QR解析)")) {
LabeledContent(
AppLocalization.string("カード番号"),
value: qr.cardNumber
)
LabeledContent(
AppLocalization.string("品目番号"),
value: CodeMatcher.format(partNumber: qr.partNumber)
value: CodeMatcher.format(partNumber: qr.partNumber, destination: .sawai)
+ (qr.partSuffix.map { "(\(AppLocalization.string("枝番")) \($0))" } ?? "")
)
LabeledContent(AppLocalization.string("納入数量"), value: quantityText(qr.deliveryQuantity))
Expand All @@ -507,7 +515,7 @@ private struct MatchEntryDetail: View {
LabeledContent(AppLocalization.string("受注者"), value: qr.ordererCode)
LabeledContent(
AppLocalization.string("部品番号"),
value: CodeMatcher.format(partNumber: qr.partNumber)
value: CodeMatcher.format(partNumber: qr.partNumber, destination: .molten)
)
LabeledContent(AppLocalization.string("納品番号"), value: qr.deliveryNumber)
LabeledContent(AppLocalization.string("納入先"), value: qr.deliveryDestination)
Expand All @@ -526,6 +534,55 @@ private struct MatchEntryDetail: View {
value: qr.formattedInstructionTime ?? "-"
)
}
} else if let qr = entry.densoRecord {
// デンソーのかんばんは項目構成が変わりうるので、無い項目は行ごと出さない。
Section(AppLocalization.string("納品書情報(QR解析)")) {
if let formType = qr.formType {
LabeledContent(AppLocalization.string("帳票区分"), value: formType)
}
LabeledContent(
AppLocalization.string("部品番号"),
value: CodeMatcher.format(partNumber: qr.partNumber, destination: .denso)
)
if let packagingCode = qr.packagingCode {
LabeledContent(AppLocalization.string("包装"), value: packagingCode)
}
LabeledContent(
AppLocalization.string("収容数"),
value: appLanguage.formatInteger(qr.packQuantity)
)
if let nextProcess = qr.nextProcess {
LabeledContent(AppLocalization.string("次区"), value: nextProcess)
}
if let instructionCode = qr.instructionCode {
LabeledContent(AppLocalization.string("指示"), value: instructionCode)
}
LabeledContent(
AppLocalization.string("かんばん連番"),
value: qr.kanbanSerial
)
if let managementNumber = qr.managementNumber {
LabeledContent(AppLocalization.string("管理番号"), value: managementNumber)
}
if let deliveryDate = qr.formattedDeliveryDate {
LabeledContent(AppLocalization.string("納入日"), value: deliveryDate)
}
if let deliveryRun = qr.deliveryRun {
LabeledContent(AppLocalization.string("便"), value: deliveryRun)
}
if let instructedQuantity = qr.instructedQuantity {
LabeledContent(
AppLocalization.string("指示数"),
value: appLanguage.formatInteger(instructedQuantity)
)
}
if let itemNumber = qr.itemNumber {
LabeledContent(AppLocalization.string("アイテムNo"), value: itemNumber)
}
if let receivingCode = qr.receivingCode {
LabeledContent(AppLocalization.string("受入"), value: receivingCode)
}
}
}

if let tag = entry.barcodePayload.flatMap(TagBarcodeRecord.parse) {
Expand Down
9 changes: 9 additions & 0 deletions ios/CodeMatch/Models/HistoryModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,15 @@ extension MatchHistoryEntry {
return MoltenQRRecord.parse(qrPayload)
}

/// デンソーのかんばんQR(JAMA自己記述形式)として解析した結果。
/// 別の仕向地やQR全文を持たない旧履歴ではnil。
/// `KanbanQRRecord.parse` は寛容なのでデンソーのQRも澤井製作所として解析できてしまう。
/// 表示側は必ずこの仕向地ガード付きのプロパティを通す。
var densoRecord: DensoKanbanRecord? {
guard let qrPayload, Destination.detect(qrPayload: qrPayload) == .denso else { return nil }
return DensoKanbanRecord.parse(qrPayload)
}

/// この記録がどの箱を検査したかを表す箱固有キー。仕向地ごとの作り方は `BoxIdentity` に従う。
/// QR全文を持たない旧履歴や、モルテンでCode 128全文を持たない記録ではnil。
var boxIdentity: String? {
Expand Down
7 changes: 0 additions & 7 deletions ios/CodeMatch/Models/ScanModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -186,13 +186,6 @@ enum CodeMatcher {
return qrPart == barcodePart ? .match : .mismatch
}

/// 品番を現品票の表記へ整形する(仕向地不明の従来規則)。
/// 10桁は4-2-4 (`BCJH5281GG` → `BCJH-52-81GG`)、9桁は4-2-3 (`PAF115422` → `PAF1-15-422`)。
/// それ以外の桁数はそのまま返す。
static func format(partNumber: String) -> String {
format(partNumber: partNumber, destination: nil)
}

/// 品番を仕向地の現品票の表記へ整形する。
/// デンソーの10桁は6-4 (`8601507722` → `860150-7722`)。
/// 澤井製作所・モルテン・仕向地未確定は従来の長さ規則(10→4-2-4 / 9→4-2-3)。
Expand Down
224 changes: 224 additions & 0 deletions ios/CodeMatch/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -5704,6 +5704,230 @@
}
}
}
},
"帳票区分" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Form type"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "帳票区分"
}
}
}
},
"包装" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Packaging"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "包装"
}
}
}
},
"次区" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Next process"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "次区"
}
}
}
},
"指示" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Instruction"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "指示"
}
}
}
},
"かんばん連番" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Kanban serial"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "かんばん連番"
}
}
}
},
"管理番号" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Management number"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "管理番号"
}
}
}
},
"納入日" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Delivery date"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "納入日"
}
}
}
},
"便" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Delivery run"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "便"
}
}
}
},
"アイテムNo" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Item No."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "アイテムNo"
}
}
}
},
"受入" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Receiving"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "受入"
}
}
}
},
"かんばん連番: %@" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Kanban serial: %@"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "かんばん連番: %@"
}
}
}
},
"部品番号: %@ 収容数: %lld 指示数: %@" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Part number: %1$@, pack quantity: %2$lld, instructed quantity: %3$@"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "部品番号: %1$@ 収容数: %2$lld 指示数: %3$@"
}
}
}
},
"次区: %@ 指示: %@ 納入日: %@ 便: %@" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Next process: %1$@, instruction: %2$@, delivery date: %3$@, delivery run: %4$@"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "次区: %1$@ 指示: %2$@ 納入日: %3$@ 便: %4$@"
}
}
}
},
"管理番号: %@ アイテムNo: %@ 受入: %@" : {
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Management number: %1$@, item No.: %2$@, receiving: %3$@"
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "管理番号: %1$@ アイテムNo: %2$@ 受入: %3$@"
}
}
}
}
},
"version" : "1.0"
Expand Down
Loading
Loading