All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.gematik.bbriccs.fhir.de.value.KVNR Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2024 gematik GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package de.gematik.bbriccs.fhir.de.value;

import static java.text.MessageFormat.format;

import de.gematik.bbriccs.fhir.builder.FakerBrick;
import de.gematik.bbriccs.fhir.coding.SemanticValue;
import de.gematik.bbriccs.fhir.coding.WithChecksum;
import de.gematik.bbriccs.fhir.coding.exceptions.InvalidSystemException;
import de.gematik.bbriccs.fhir.coding.exceptions.MissingFieldException;
import de.gematik.bbriccs.fhir.de.DeBasisProfilNamingSystem;
import de.gematik.bbriccs.fhir.de.valueset.InsuranceTypeDe;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import lombok.EqualsAndHashCode;
import lombok.val;
import one.util.streamex.StreamEx;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Resource;

/**
 * Krankenversichertennummer
 */
@EqualsAndHashCode(callSuper = true)
public class KVNR extends SemanticValue implements WithChecksum {

  private static final List KVNR_SYSTEMS =
      List.of(
          DeBasisProfilNamingSystem.SID_KVID_GKV,
          DeBasisProfilNamingSystem.SID_KVID_PKV,
          DeBasisProfilNamingSystem.KVID);
  private static final Pattern KVNR_PATTERN = Pattern.compile("^([A-Z])(\\d{8})(\\d)$");

  private KVNR(DeBasisProfilNamingSystem namingSystem, String value) {
    super(namingSystem, value);
  }

  public InsuranceTypeDe getInsuranceType() {
    return switch (this.getSystem()) {
      case KVID, SID_KVID_GKV -> InsuranceTypeDe.GKV;
      case SID_KVID_PKV -> InsuranceTypeDe.PKV;
      default -> throw new InvalidSystemException(this.getClass(), this.getSystem());
    };
  }

  public boolean isGkv() {
    return this.getSystem()
        .matches(DeBasisProfilNamingSystem.SID_KVID_GKV, DeBasisProfilNamingSystem.KVID);
  }

  public boolean isPkv() {
    return this.getSystem().matches(DeBasisProfilNamingSystem.SID_KVID_PKV);
  }

  @Override
  public Identifier asIdentifier() {
    return asIdentifier(true);
  }

  public Identifier asIdentifier(boolean withCoding) {
    return this.asIdentifier(this.getSystem(), withCoding);
  }

  @Override
  public Identifier asIdentifier(DeBasisProfilNamingSystem system) {
    return asIdentifier(system, true);
  }

  public Identifier asIdentifier(DeBasisProfilNamingSystem system, boolean withCoding) {
    val identifier = super.asIdentifier(system);

    if (withCoding) identifier.getType().addCoding(this.getInsuranceType().asCoding());
    return identifier;
  }

  @Override
  public boolean isValid() {
    val kvnr = getValue();
    if (kvnr == null) return false;

    val matcher = KVNR_PATTERN.matcher(kvnr);
    if (!matcher.matches()) return false;

    val calculated = getCalculateCheckNumber(matcher.group(0).charAt(0), matcher.group(2));

    return calculated == getChecksum();
  }

  @Override
  public int getChecksum() {
    val value = getValue();
    return Character.getNumericValue(value.charAt(value.length() - 1));
  }

  public static KVNR random() {
    val faker = FakerBrick.getGerman();
    if (faker.bool().bool()) return randomGkv();
    else return randomPkv();
  }

  public static KVNR randomPkv() {
    return forPkv(randomStringValue());
  }

  public static KVNR randomGkv() {
    return forGkv(randomStringValue());
  }

  public static KVNR forPkv(String value) {
    return from(DeBasisProfilNamingSystem.SID_KVID_PKV, value);
  }

  public static KVNR forGkv(String value) {
    return from(DeBasisProfilNamingSystem.SID_KVID_GKV, value);
  }

  public static KVNR from(String value) {
    return from(DeBasisProfilNamingSystem.KVID, value);
  }

  public static KVNR from(DeBasisProfilNamingSystem namingSystem, String value) {
    return new KVNR(namingSystem, value);
  }

  public static Optional extractFrom(Identifier identifier) {
    return extractFrom(List.of(identifier));
  }

  public static Optional extractFrom(List identifiers) {
    return StreamEx.of(identifiers)
        .cross(KVNR_SYSTEMS)
        .filter(entry -> entry.getValue().matches(entry.getKey()))
        .map(
            entry -> {
              val system = entry.getValue();
              val identifierValue = entry.getKey().getValue();
              return new KVNR(system, identifierValue);
            })
        .findFirst();
  }

  public static 

KVNR extractFromOrThrow( Class

parent, Identifier identifier) { return extractFromOrThrow(parent, List.of(identifier)); } public static

KVNR extractFromOrThrow( Class

parent, List identifiers) { return extractFrom(identifiers).orElseThrow(() -> new MissingFieldException(parent, "KVNR")); } public static String randomStringValue() { val faker = FakerBrick.getGerman(); val capLetter = faker.regexify("[A-Z]{1}").charAt(0); val numbers = faker.regexify("[0-9]{8}"); val checkNum = getCalculateCheckNumber(capLetter, numbers); return format("{0}{1}{2}", capLetter, numbers, checkNum); } /** * get the chunked KVNR without the check number and calculate the check number * * @param capLetter is the leading capital letter [A-Z] * @param numbers 8 random digits * @return the calculated check number */ private static int getCalculateCheckNumber(char capLetter, String numbers) { val letterValue = String.format("%02d", capLetter - 64); val rawNumber = format("{0}{1}", letterValue, numbers); val idx = new AtomicInteger(); var sum = new AtomicInteger(); rawNumber .chars() .map(asciiValue -> asciiValue - 48) .forEach( value -> { if (idx.getAndIncrement() % 2 == 1) value *= 2; if (value > 9) value -= 9; sum.addAndGet(value); }); return sum.get() % 10; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy