///|
pub struct ShipmentProjection {
  gtin : String?
  lot : String?
  serial : String?
  expiration : String?
  sscc : String?
  quantity : String?
} derive(Debug, Eq)

///|
pub fn project_shipment(message : GS1Message) -> ShipmentProjection {
  let expiration = match message.normalized_element("17") {
    Some(value) => value.date_value
    None => None
  }
  {
    gtin: message.first_value("01"),
    lot: message.first_value("10"),
    serial: message.first_value("21"),
    expiration,
    sscc: message.first_value("00"),
    quantity: message.first_value("30"),
  }
}

///|
pub fn ShipmentProjection::is_traceable(self : ShipmentProjection) -> Bool {
  self.gtin is Some(_) && self.lot is Some(_) && self.expiration is Some(_)
}

///|
pub fn ShipmentProjection::identity(self : ShipmentProjection) -> String {
  match self.gtin {
    Some(gtin) =>
      match self.serial {
        Some(serial) => "\{gtin}/\{serial}"
        None =>
          match self.lot {
            Some(lot) => "\{gtin}/\{lot}"
            None => gtin
          }
      }
    None => "unknown"
  }
}