Skip to content

Commit

Permalink
Merge pull request #184 from b123400/fix-179
Browse files Browse the repository at this point in the history
Read AVH number, fix issue with insurance ean
  • Loading branch information
zdavatz authored Dec 28, 2024
2 parents 2b95e76 + fffe679 commit 8af0ae3
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 67 deletions.
77 changes: 48 additions & 29 deletions AmiKoDesitin/Base.lproj/PatientViewController.xib

Large diffs are not rendered by default.

9 changes: 6 additions & 3 deletions AmiKoDesitin/EPrescription/EPrescription.m
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ - (ZurRosePrescription *)toZurRosePrescription {
ZurRosePrescription *prescription = [[ZurRosePrescription alloc] init];

prescription.issueDate = self.date;
prescription.prescriptionNr = self.prescriptionId;
prescription.prescriptionNr = [NSString stringWithFormat:@"%09d", arc4random_uniform(1000000000)];
prescription.remark = self.rmk;
prescription.validity = self.valDt; // ???

Expand Down Expand Up @@ -226,11 +226,13 @@ - (ZurRosePrescription *)toZurRosePrescription {
: [self.patientLang.lowercaseString hasPrefix:@"fr"] ? 2
: [self.patientLang.lowercaseString hasPrefix:@"it"] ? 3
: 1;
patient.coverCardId = @"";
patient.patientNr = @"";

NSString *insuranceEan = nil;
for (EPrescriptionPatientId *pid in self.patientIds) {
if ([pid.type isEqual:@(1)]) {
patient.coverCardId = pid.value;
patient.patientNr = pid.value; // ???
insuranceEan = pid.value;
}
}

Expand All @@ -252,6 +254,7 @@ - (ZurRosePrescription *)toZurRosePrescription {
product.quantity = medi.nbPack.intValue; // ???
product.remark = medi.appInstr;
product.insuranceBillingType = 1;
product.insuranceEanId = insuranceEan;

BOOL repetition = NO;
NSMutableArray<ZurRosePosology *> *poses = [NSMutableArray array];
Expand Down
1 change: 1 addition & 0 deletions AmiKoDesitin/Model.xcdatamodeld/Model.xcdatamodel/contents
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="23231" systemVersion="23H124" minimumToolsVersion="Automatic" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
<entity name="Patient" representedClassName="PatientModel" syncable="YES">
<attribute name="ahvNumber" optional="YES" attributeType="String"/>
<attribute name="birthDate" optional="YES" attributeType="String"/>
<attribute name="city" optional="YES" attributeType="String"/>
<attribute name="country" optional="YES" attributeType="String"/>
Expand Down
2 changes: 2 additions & 0 deletions AmiKoDesitin/Patient.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#define KEY_AMK_PAT_EMAIL @"email_address"
#define KEY_AMK_PAT_HEALTH_CARD_NUMBER @"health_card_number"
#define KEY_AMK_PAT_INSURANCE_GLN @"insurance_gln"
#define KEY_AMK_PAT_INSURANCE_AHV_NUMBER @"ahv_number"

@interface Patient : NSObject

Expand All @@ -43,6 +44,7 @@
@property (atomic, copy) NSString *emailAddress;
@property (atomic, copy) NSString *healthCardNumber;
@property (atomic, copy) NSString *insuranceGLN;
@property (atomic, copy) NSString *ahvNumber;

// Only available when patient is read from database
@property (nonatomic, strong, nullable) NSDate *timestamp;
Expand Down
5 changes: 4 additions & 1 deletion AmiKoDesitin/Patient.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ @implementation Patient
@synthesize emailAddress;
@synthesize healthCardNumber;
@synthesize insuranceGLN;
@synthesize ahvNumber;

- (void)importFromDict:(NSDictionary *)dict
{
Expand All @@ -44,6 +45,7 @@ - (void)importFromDict:(NSDictionary *)dict
emailAddress = [self getString:KEY_AMK_PAT_EMAIL orNilFromDict:dict];
healthCardNumber = [self getString:KEY_AMK_PAT_HEALTH_CARD_NUMBER orNilFromDict:dict];
insuranceGLN = [self getString:KEY_AMK_PAT_INSURANCE_GLN orNilFromDict:dict];
ahvNumber = [self getString:KEY_AMK_PAT_INSURANCE_AHV_NUMBER orNilFromDict:dict];
}

- (NSDictionary <NSString *, NSString *> *)dictionaryRepresentation {
Expand All @@ -62,7 +64,8 @@ - (void)importFromDict:(NSDictionary *)dict
[patientDict setObject:self.phoneNumber ?: @"" forKey:KEY_AMK_PAT_PHONE];
[patientDict setObject:self.emailAddress ?: @"" forKey:KEY_AMK_PAT_EMAIL];
[patientDict setObject:self.healthCardNumber ?: @"" forKey:KEY_AMK_PAT_HEALTH_CARD_NUMBER];
[patientDict setObject:self.insuranceGLN forKey:KEY_AMK_PAT_INSURANCE_GLN];
[patientDict setObject:self.insuranceGLN ?: @"" forKey:KEY_AMK_PAT_INSURANCE_GLN];
[patientDict setObject:self.ahvNumber ?: @"" forKey:KEY_AMK_PAT_INSURANCE_AHV_NUMBER];
return patientDict;
}

Expand Down
3 changes: 2 additions & 1 deletion AmiKoDesitin/PatientViewController+smartCard.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

#import "PatientViewController.h"

#define NUMBER_OF_BOXES_FOR_OCR 4
#define NUMBER_OF_BOXES_FOR_OCR 5

#import "CameraViewController.h"

Expand All @@ -19,6 +19,7 @@ struct scannedResults {
NSString *dateString;
NSString *sexString;
NSString *bagNumber;
NSString *ahvNumber;
};

#pragma mark - class extension
Expand Down
73 changes: 44 additions & 29 deletions AmiKoDesitin/PatientViewController+smartCard.m
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ - (NSArray *)visionDetectTextBoundingBoxes:(CIImage*)image
NSArray *langs = [VNRecognizeTextRequest supportedRecognitionLanguagesForTextRecognitionLevel:VNRequestTextRecognitionLevelAccurate
revision:VNRecognizeTextRequestRevision1
error:&error];
NSLog(@"%@", langs);
// NSLog(@"%@", langs);

VNRecognizeTextRequest *textRequest = [VNRecognizeTextRequest new];
textRequest.recognitionLevel = VNRequestTextRecognitionLevelAccurate;
Expand Down Expand Up @@ -276,13 +276,22 @@ - (NSArray *)visionDetectTextBoundingBoxes:(CIImage*)image
if (box.origin.x > thresholdX)
#endif
{
BOOL shouldSkip = YES;
// Handle BAG number, which is not at the right side of the card
// 5 digit and all number
if (s.length == 5 && [[NSString stringWithFormat:@"%05d",[s intValue]] isEqual:s]) {
if (box.origin.x > 0.9) {
continue;
if (box.origin.x < 0.9) {
shouldSkip = NO;
}
} else {
} else if (s.length == 16) {
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"^[0-9]{3}\\.[0-9]{4}\\.[0-9]{4}\\.[0-9]{2}$" options:0 error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:s options:0 range:NSMakeRange(0, s.length)];
if (match) {
shouldSkip = NO;
}
}
if (shouldSkip) {
continue;
}
}
Expand Down Expand Up @@ -333,22 +342,6 @@ - (NSArray *)visionDetectTextBoundingBoxes:(CIImage*)image

- (NSArray *)analyzeVisionBoxedWords:(NSArray *)allBoxes
{
// Always put BAG number at last
NSInteger bagNumberIndex = -1;
for (NSInteger i = 0; i < allBoxes.count; i++) {
if ([allBoxes[i][@"text"] length] == 5) {
bagNumberIndex = i;
break;
}
}
if (bagNumberIndex >= 0) {
NSMutableArray *mAllBoxes = [allBoxes mutableCopy];
NSDictionary *bagNumber = mAllBoxes[bagNumberIndex];
[mAllBoxes removeObjectAtIndex:bagNumberIndex];
[mAllBoxes addObject:bagNumber];
allBoxes = mAllBoxes;
}

NSUInteger n = [allBoxes count];
if (n < NUMBER_OF_BOXES_FOR_OCR) {
return allBoxes;
Expand Down Expand Up @@ -397,18 +390,35 @@ - (NSArray *)analyzeVisionBoxedWords:(NSArray *)allBoxes

return p1.origin.x >= p2.origin.x;
#else
if ([obj1[@"text"] length] == 5) {
return NSOrderedDescending;
}
if ([obj2[@"text"] length] == 5) {
return NSOrderedAscending;
}
if (p1.origin.y == p2.origin.y)
return NSOrderedSame;

return p1.origin.y < p2.origin.y;
#endif
}];

// At this point, the first one should be name, last one should be date string,
// but we are not sure about the middle ones, at they are layed out horizontally
NSDictionary *name = [boxedWords firstObject];
NSDictionary *dateString = [boxedWords lastObject];

boxedWords = [boxedWords subarrayWithRange:NSMakeRange(1, NUMBER_OF_BOXES_FOR_OCR - 2)];
boxedWords = [boxedWords sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *obj1, NSDictionary *obj2) {
CGRect p1 = [obj1[@"box"] CGRectValue];
CGRect p2 = [obj2[@"box"] CGRectValue];
#ifdef VN_BOXES_NEED_XY_SWAP
if (p1.origin.y == p2.origin.y)
return NSOrderedSame;

return p1.origin.y >= p2.origin.y;
#else
if (p1.origin.x == p2.origin.x)
return NSOrderedSame;

return p1.origin.x >= p2.origin.x;
#endif
}];
boxedWords = [@[name] arrayByAddingObjectsFromArray:[boxedWords arrayByAddingObject:dateString]];

return boxedWords;
}
Expand Down Expand Up @@ -463,9 +473,12 @@ - (BOOL)validateOcrResults:(NSArray *)ocrResults
if (![_NumericOnly isSupersetOfSet: myStringSet]) {
return NO;
}

NSString *bagNumber = ocrResults[2][@"text"];
NSString *ahvNumber = ocrResults[3][@"text"];

// Validate third line /////////////////////////////////////////////////////
d = ocrResults[2];
d = ocrResults[4];
s = d[@"text"];
NSArray *line2Array = [s componentsSeparatedByString:@" "];
if ([line2Array count] < 2) {
Expand All @@ -486,15 +499,14 @@ - (BOOL)validateOcrResults:(NSArray *)ocrResults
{
return NO;
}

NSString *bagNumber = ocrResults[3][@"text"];

savedOcr.familyName = familyName;
savedOcr.givenName = givenName;
savedOcr.cardNumberString = cardNumberString;
savedOcr.dateString = dateString;
savedOcr.sexString = sexString;
savedOcr.bagNumber = bagNumber;
savedOcr.ahvNumber = ahvNumber;

return YES;
}
Expand All @@ -513,11 +525,14 @@ - (void)lastVideoFrame:(NSNotification *)notification
incompletePatient.uniqueId = [incompletePatient generateUniqueID];
incompletePatient.healthCardNumber = savedOcr.cardNumberString;
incompletePatient.insuranceGLN = [self bagNumberToInsuranceGLN:savedOcr.bagNumber];
incompletePatient.ahvNumber = savedOcr.ahvNumber;

if ([savedOcr.sexString isEqualToString:@"M"])
incompletePatient.gender = KEY_AMK_PAT_GENDER_M;
else if ([savedOcr.sexString isEqualToString:@"F"])
incompletePatient.gender = KEY_AMK_PAT_GENDER_F;

NSLog(@"ahv %@", savedOcr.ahvNumber);

#ifdef TAP_TO_END_CARD_OCR
[self resetAllFields];
Expand Down
1 change: 1 addition & 0 deletions AmiKoDesitin/PatientViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
IBOutlet UITextField *mEmail;
IBOutlet UITextField *mHealthCardNumber;
IBOutlet UITextField *mInsuranceGLN;
IBOutlet UITextField *mAHVNumber;
IBOutlet UISegmentedControl *mSex;
}

Expand Down
9 changes: 8 additions & 1 deletion AmiKoDesitin/PatientViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ - (void) resetFieldsColors
mSex.backgroundColor =
mEmail.backgroundColor =
mHealthCardNumber.backgroundColor =
mInsuranceGLN.backgroundColor = [UIColor secondarySystemBackgroundColor];
mInsuranceGLN.backgroundColor =
mAHVNumber.backgroundColor = [UIColor secondarySystemBackgroundColor];
}

- (UIColor *)getInvalidFieldColor
Expand Down Expand Up @@ -266,6 +267,7 @@ - (void) resetAllFields
[mEmail setText:@""];
[mHealthCardNumber setText:@""];
[mInsuranceGLN setText:@""];
[mAHVNumber setText:@""];
[mSex setSelectedSegmentIndex:UISegmentedControlNoSegment];

mPatientUUID = nil;
Expand Down Expand Up @@ -318,6 +320,10 @@ - (void) setAllFields:(Patient *)p
if (p.insuranceGLN) {
[mInsuranceGLN setText:p.insuranceGLN];
}

if (p.ahvNumber) {
[mAHVNumber setText:p.ahvNumber];
}

if (p.uniqueId)
mPatientUUID = p.uniqueId;
Expand Down Expand Up @@ -363,6 +369,7 @@ - (Patient *) getAllFields
patient.emailAddress = [mEmail text];
patient.healthCardNumber = [mHealthCardNumber text];
patient.insuranceGLN = [mInsuranceGLN text];
patient.ahvNumber = [mAHVNumber text];

switch ([mSex selectedSegmentIndex]) {
case UISegmentedControlNoSegment:
Expand Down
13 changes: 13 additions & 0 deletions AmiKoDesitin/Persistence/MLPersistenceManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,9 @@ - (NSString *)upsertPatient:(Patient *)patient withTimestamp:(NSDate*)date updat
NSError *error = nil;
if (patient.uniqueId.length) {
PatientModel *p = [self getPatientModelWithUniqueID:patient.uniqueId];
if (p == nil) {
p = [self findSimilarPatientModelByNameAndDOB:patient];
}
if (p != nil) {
p.weightKg = patient.weightKg;
p.heightCm = patient.heightCm;
Expand Down Expand Up @@ -581,6 +584,16 @@ - (Patient *) getPatientWithUniqueID:(NSString *)uniqueID {
return [[self getPatientModelWithUniqueID:uniqueID] toPatient];
}

- (PatientModel *)findSimilarPatientModelByNameAndDOB:(Patient *)patient {
NSError *error = nil;
NSManagedObjectContext *context = [[self coreDataContainer] viewContext];
NSFetchRequest *req = [PatientModel fetchRequest];
req.predicate = [NSPredicate predicateWithFormat:@"familyName == %@ AND givenName == %@ AND birthDate == %@", patient.familyName, patient.givenName, patient.birthDate];
req.fetchLimit = 1;
NSArray<PatientModel *> *patientModels = [context executeFetchRequest:req error:&error];
return [patientModels firstObject];
}

# pragma mark - Favourites

- (NSURL *)favouritesFile {
Expand Down
2 changes: 1 addition & 1 deletion AmiKoDesitin/Prescription.m
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ - (ZurRosePrescription *)toZurRosePrescription {
patient.email = self.patient.emailAddress;
patient.langCode = [[MLConstants databaseLanguage] isEqual:@"de"] ? 1 : 2;
patient.coverCardId = self.patient.healthCardNumber ?: @"";
patient.patientNr = self.patient.insuranceGLN;
patient.patientNr = self.patient.ahvNumber;

NSMutableArray<ZurRoseProduct*> *products = [NSMutableArray array];
for (Product *m in self.medications) {
Expand Down
4 changes: 2 additions & 2 deletions AmiKoDesitin/PreviewView.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
// Following 4 defines in the range 0..1
#define cardROI_X 0.0f
#define cardROI_Y (cardIgnoreTop_mm / cardHeight_mm)
#define cardROI_W (60.0/cardWidth_mm)
#define cardROI_W (cardWidth_mm/cardWidth_mm) // We need the full width for AHV number
#define cardROI_H ((cardHeight_mm - cardIgnoreTop_mm)/cardHeight_mm)

#ifdef CROP_IMAGE_TO_CARD_ROI
#define rejectBoxWidthFraction 0.157f // observed threshold
#define rejectBoxWidthFraction 0.047f // observed threshold
#else
#define rejectBoxWidthFraction 0.047f // observed threshold
#endif
Expand Down
2 changes: 2 additions & 0 deletions PatientModel+CoreDataClass.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ - (void)importFromPatient:(Patient *)p timestamp:(NSDate *)timestamp {
self.emailAddress = p.emailAddress;
self.healthCardNumber = p.healthCardNumber;
self.insuranceGLN = p.insuranceGLN;
self.ahvNumber = p.ahvNumber;
}

- (Patient *)toPatient {
Expand All @@ -48,6 +49,7 @@ - (Patient *)toPatient {
p.timestamp = self.timestamp;
p.healthCardNumber = self.healthCardNumber;
p.insuranceGLN = self.insuranceGLN;
p.ahvNumber = self.ahvNumber;
return p;
}

Expand Down
1 change: 1 addition & 0 deletions PatientModel+CoreDataProperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nullable, nonatomic, copy) NSString *zipCode;
@property (nullable, nonatomic, copy) NSString *healthCardNumber;
@property (nullable, nonatomic, copy) NSString *insuranceGLN;
@property (nullable, nonatomic, copy) NSString *ahvNumber;
@end

NS_ASSUME_NONNULL_END
1 change: 1 addition & 0 deletions PatientModel+CoreDataProperties.m
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ @implementation PatientModel (CoreDataProperties)
@dynamic zipCode;
@dynamic healthCardNumber;
@dynamic insuranceGLN;
@dynamic ahvNumber;

@end

0 comments on commit 8af0ae3

Please sign in to comment.