diff --git a/DUREX Vendor Control/Base.lproj/DatePickerViewController.xib b/DUREX Vendor Control/Base.lproj/DatePickerViewController.xib index 3465ebf..3041189 100644 --- a/DUREX Vendor Control/Base.lproj/DatePickerViewController.xib +++ b/DUREX Vendor Control/Base.lproj/DatePickerViewController.xib @@ -13,11 +13,11 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/DUREX Vendor Control/FirstAppExample/EMDevicePickerViewController.m b/DUREX Vendor Control/FirstAppExample/EMDevicePickerViewController.m index 54b7333..c0b1605 100644 --- a/DUREX Vendor Control/FirstAppExample/EMDevicePickerViewController.m +++ b/DUREX Vendor Control/FirstAppExample/EMDevicePickerViewController.m @@ -34,6 +34,7 @@ - (void)viewDidLoad { [super viewDidLoad]; + [[EMConnectionManager sharedManager] setBackgroundUpdatesEnabled:TRUE]; [[EMConnectionListManager sharedManager] addObserver:self forKeyPath:@"devices" options:0 context:NULL]; } @@ -105,7 +106,7 @@ -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - //[self performSegueWithIdentifier:@"ConnectionSegue" sender:self]; + [self performSegueWithIdentifier:@"ConnectionSegue" sender:self]; if(![[[[tableView cellForRowAtIndexPath:indexPath] textLabel] text] isEqualToString:NSLocalizedString(@"Searching for devices...",nil)]) { [self _showConnectingView]; diff --git a/DUREX Vendor Control/MenuTableViewController.h b/DUREX Vendor Control/MenuTableViewController.h index 585b8f9..2aa92f9 100644 --- a/DUREX Vendor Control/MenuTableViewController.h +++ b/DUREX Vendor Control/MenuTableViewController.h @@ -13,6 +13,7 @@ #import "DatePickerViewController.h" #import "PriceChangerViewController.h" #import "NameChangerViewController.h" +#import "DateRangePickerViewController.h" #import "Sensors.h" #import "SalesLog.h" #import "UIView+Toast.h" @@ -55,12 +56,18 @@ enum { REPORT, } navigationLevel; -@interface MenuTableViewController : UITableViewController +enum { + SALES_LOG = 0, + INCIDENT_LOG, +} logType; + +@interface MenuTableViewController : UITableViewController @property (strong,nonatomic) Stack *parentLayout; @property (strong,nonatomic) DatePickerViewController *datePickerViewController; @property (strong,nonatomic) PriceChangerViewController *priceChangerViewController; @property (strong,nonatomic) NameChangerViewController *nameChangerViewController; +@property (strong,nonatomic) DateRangePickerViewController *dateRangePickerViewController; @property (strong,nonatomic) Sensors *sensorStatus; @property (strong,nonatomic) SalesLog *salesLog; @property (strong,nonatomic) Sale *currentSale; diff --git a/DUREX Vendor Control/MenuTableViewController.m b/DUREX Vendor Control/MenuTableViewController.m index f35a2f6..33aa3f6 100644 --- a/DUREX Vendor Control/MenuTableViewController.m +++ b/DUREX Vendor Control/MenuTableViewController.m @@ -42,6 +42,7 @@ @property const NSMutableArray *currentStructure; @property const NSMutableArray *currentHeaders; +@property uint8_t requestedLog; @end @implementation MenuTableViewController @@ -108,19 +109,8 @@ return TRUE; } -- (Boolean) generateSaleListNavLevel +- (void) generateSaleListNavLevel { - //Initialize sales log - [self setSalesLog:[[SalesLog alloc]init]]; - - //LAUNCH DATE RANGE SELECTOR - NSString *salesData = [_protocol readSalesLog: nil : nil]; - if(salesData == nil) - { - NSLog(@"[MenuTableViewController.m]: Error reading sales log"); - return FALSE; - } - [[self salesLog] setResponseValue:salesData]; NSMutableArray *dateArray = [[NSMutableArray alloc] init]; for(int i = 0; i < [[[self salesLog] sales]count]; i++) { @@ -133,7 +123,6 @@ [self setSaleListElements:[[NSMutableArray alloc] initWithArray:dateArray]]; [self setSaleListStructure:[[NSMutableArray alloc] initWithObjects:[NSNumber numberWithInt:[dateArray count]], nil]]; [self setSaleListHeaders:nil]; - return TRUE; } - (Boolean) generateSaleNavLevel : (NSInteger) numSale @@ -312,7 +301,7 @@ //DUREX protocol if(![_protocol establishConnection]) { - UIAlertView* alert = [[UIAlertView alloc] initWithTitle:@"Communication error" message:@"Error while trying to connect to the device" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Communication error",nil) message:NSLocalizedString(@"Error while trying to connect to the device",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; [alert show]; UIViewController *previous = [[[self navigationController] viewControllers] objectAtIndex:[[[self navigationController] viewControllers] count]-2]; [[self navigationController] popToViewController:previous animated:YES]; @@ -521,7 +510,7 @@ NSLog(@"[MenuTableViewController.m]: Changing to navLevel: MAINTENANCE"); if([self generateMaintenanceLevel]) { - [NSThread sleepForTimeInterval:1]; + [NSThread sleepForTimeInterval:1]; //HACK! [self changeNavLevel:MAINTENANCE:TRUE]; } else @@ -554,16 +543,20 @@ } else if([cellName isEqualToString:NSLocalizedString(@"Sales log", nil)]) { - [NSThread sleepForTimeInterval:1]; - NSLog(@"[MenuTableViewController.m]: Changing to navLevel: SALE_LIST"); - if([self generateSaleListNavLevel]) + [self setRequestedLog:SALES_LOG]; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { - [self changeNavLevel:SALE_LIST:TRUE]; + self.dateRangePickerViewController = [[DateRangePickerViewController alloc] initWithNibName:@"DateRangePickerViewController_iPad" bundle:nil]; + self.dateRangePickerViewController.delegate = self; + [self.dateRangePickerViewController showInView:self.navigationController.view animated:YES]; } else { - NSLog(@"[MenuTableViewController.m]: Error while changing to navLevel: SALE_LIST"); + self.dateRangePickerViewController = [[DateRangePickerViewController alloc] initWithNibName:@"DateRangePickerViewController" bundle:nil]; + self.dateRangePickerViewController.delegate = self; + [self.dateRangePickerViewController showInView:self.navigationController.view animated:YES]; } + } else if([cellName isEqualToString:NSLocalizedString(@"Send report", nil)]) { @@ -712,7 +705,7 @@ } //PARSE AND REMOVE TAG NSInteger lastPos = [cellText rangeOfString:@"]"].location; - NSInteger cellTag = [[cellText substringWithRange:NSMakeRange(1,lastPos)] intValue]; + NSInteger cellTag = [[cellText substringWithRange:NSMakeRange(1,lastPos-1)] intValue]; [cell setTag:cellTag]; [cellText setString:[cellText substringFromIndex:lastPos+1]]; //SET FINAL TEXT @@ -1086,20 +1079,108 @@ { NSLog(@"[MenuTableViewController.m]: %@", data); //Channel,Code,Price - int channel = [[data objectAtIndex:0] intValue]; - int code = [[data objectAtIndex:1] intValue]; - NSArray *price = [[data objectAtIndex:2] componentsSeparatedByString:@","]; - [_protocol updatePrice:channel :code :[[price objectAtIndex:0] intValue] :[[price objectAtIndex:1] intValue]]; + NSString *channelString = [data objectAtIndex:0]; + NSString *codeString = [data objectAtIndex:1]; + NSString *priceString = [data objectAtIndex:2]; + if(![[NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"^\\d+(\\.\\d+)?$"] options:0 error:NULL] numberOfMatchesInString:priceString options:0 range:NSMakeRange(0,[priceString length])]) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Entered price has an invalid format",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else if([channelString length] == 0) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Missing channel",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else if([codeString length] == 0) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Missing product code",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else if(![[NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"\\d+"] options:0 error:NULL] numberOfMatchesInString:channelString options:0 range:NSMakeRange(0,[channelString length])]) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Entered channel has an invalid format",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else if(![[NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"\\d+"] options:0 error:NULL] numberOfMatchesInString:codeString options:0 range:NSMakeRange(0,[codeString length])]) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Entered product code has an invalid format",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else + { + int channel = [channelString intValue]; + int code = [codeString intValue]; + NSArray *price = [priceString componentsSeparatedByString:@"."]; + [_protocol updatePrice:channel :code :[[price objectAtIndex:0] intValue] :[[price objectAtIndex:1] intValue]]; + } } - (void)passNameViewController:(PriceChangerViewController *)controller didFinishEnteringItem:(NSArray *)data { NSLog(@"[MenuTableViewController.m]: %@", data); //Channel,Code,Name - int channel = [[data objectAtIndex:0] intValue]; - int code = [[data objectAtIndex:1] intValue]; + NSString *channelString = [data objectAtIndex:0]; + NSString *codeString = [data objectAtIndex:1]; NSString *name = [data objectAtIndex:2]; - [_protocol updateProductName:channel :code :name]; + if([channelString length] == 0) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Missing channel",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else if([codeString length] == 0) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Missing product code",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else if(![[NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"\\d+"] options:0 error:NULL] numberOfMatchesInString:channelString options:0 range:NSMakeRange(0,[channelString length])]) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Entered channel has an invalid format",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else if(![[NSRegularExpression regularExpressionWithPattern:[NSString stringWithFormat:@"\\d+"] options:0 error:NULL] numberOfMatchesInString:codeString options:0 range:NSMakeRange(0,[codeString length])]) + { + UIAlertView* alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error",nil) message:NSLocalizedString(@"Entered product code has an invalid format",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil]; + [alert show]; + } + else + { + int channel = [channelString intValue]; + int code = [codeString intValue]; + [_protocol updateProductName:channel :code :name]; + } +} + +- (void) passDateRangeViewController:(DateRangePickerViewController*)controller didFinishEnteringItem:(NSDate*) from : (NSDate*) to +{ + [NSThread sleepForTimeInterval:1]; //HACK! + if([self requestedLog] == SALES_LOG) + { + NSLog(@"[MenuTableViewController.m]: Changing to navLevel: SALE_LIST"); + + //Initialize sales log + [self setSalesLog:[[SalesLog alloc]init]]; + + NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar]; + NSCalendarUnit units = NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit; + NSDateComponents *componentsFrom = [calendar components:units fromDate:from]; + NSDateComponents *componentsTo = [calendar components:units fromDate:to]; + NSString *salesData = [_protocol readSalesLog: componentsFrom : componentsTo]; + if(salesData == nil) + { + NSLog(@"[MenuTableViewController.m]: Error reading sales log"); + } + else + { + [[self salesLog] setResponseValue:salesData]; + [self generateSaleListNavLevel]; + [self changeNavLevel:SALE_LIST:TRUE]; + } + } + else if([self requestedLog] == INCIDENT_LOG) + { + + } } @end diff --git a/DUREX Vendor Control/PriceChangerViewController.m b/DUREX Vendor Control/PriceChangerViewController.m index 9282561..9a974e3 100644 --- a/DUREX Vendor Control/PriceChangerViewController.m +++ b/DUREX Vendor Control/PriceChangerViewController.m @@ -84,8 +84,25 @@ }]; } +- (void) formatPrice +{ + NSMutableString *priceText = [NSMutableString stringWithString:[[self price] text]]; + [priceText replaceOccurrencesOfString:@"," withString:@"." options:NSLiteralSearch range:NSMakeRange(0, [priceText length])]; + NSUInteger commaPos = [priceText rangeOfString:@"."].location; + if(commaPos == NSNotFound) + { + [priceText appendString:@".00"]; + } + else if(commaPos == [priceText length] - 2) + { + [priceText appendString:@"0"]; + } + [[self price] setText:priceText]; +} + - (IBAction)closePopup:(id)sender { + [self formatPrice]; NSArray *data = [[NSArray alloc] initWithObjects:[[self channel] text],[[self code] text],[[self price] text], nil]; [self.delegate passPriceViewController:self didFinishEnteringItem:data]; [self removeAnimate]; diff --git a/DUREX Vendor Control/en.lproj/Localizable.strings b/DUREX Vendor Control/en.lproj/Localizable.strings index 077a4b4..8fd9144 100644 --- a/DUREX Vendor Control/en.lproj/Localizable.strings +++ b/DUREX Vendor Control/en.lproj/Localizable.strings @@ -87,4 +87,9 @@ "Success!" = "Success!"; "Connection to server failed" = "Connection to server failed"; "Error" = "Error"; -"Product" = "Product"; \ No newline at end of file +"Product" = "Product"; +"Entered price has an invalid format" = "Entered price has an invalid format"; +"Entered product code has an invalid format" = "Entered product code has an invalid format"; +"Entered channel has an invalid format" = "Entered channel has an invalid format"; +"Missing channel" = "Missing channel"; +"Missing product code" = "Missing product code"; \ No newline at end of file diff --git a/DUREX Vendor Control/es.lproj/Localizable.strings b/DUREX Vendor Control/es.lproj/Localizable.strings index 3d53d07..0ccd65e 100644 --- a/DUREX Vendor Control/es.lproj/Localizable.strings +++ b/DUREX Vendor Control/es.lproj/Localizable.strings @@ -87,4 +87,9 @@ "Success!" = "Éxito!"; "Connection to server failed" = "Conexión al servidor fallida"; "Error" = "Error"; -"Product" = "Producto"; \ No newline at end of file +"Product" = "Producto"; +"Entered price has an invalid format" = "El precio introducido está en un formato incorrecto"; +"Entered code has an invalid format" = "El código de producto introducido está en un formato incorrecto"; +"Entered channel has an invalid format" = "El canal introducido está en un formato incorrecto"; +"Missing channel" = "Falta el canal"; +"Missing product code" = "Falta el código del producto"; \ No newline at end of file diff --git a/TODO b/TODO index 7456e86..65d291f 100644 --- a/TODO +++ b/TODO @@ -1,18 +1,17 @@ BUGS: - On date change, response is overwritten by previous query, trimming needed according to numBytes -- Sanitize input on name/price change -- Handle disconnects properly -- Month headers on sale list -- Add robustness in case of invalid length -- Add landscape layout and inverted layout TODO: - Reimplement protocol with async pattern +(WIP) - Add date range on Log request +- Handle disconnects properly - Incident class - Incident parser - A3 command - Channels and codes to 2 ciphers +- Add landscape layout and inverted layout +- Month/Year headers on sale list - Batch command files, definition, parsing and pushing them to the app - Implement user auth. Server authenticates the app ONCE on install and allows to control ONE machine (key gets validated on server and then stored on app)