Comments (8)
Hi blackfrog, I would be interested in the code. I have stats kept on my device by an older version of AppSales and would like to upgrade and migrate to iPad. Can you post the code somehow? Thanks
from appsales-mobile.
Here is the first version of my master.log import/export code. It's a brute force implementation that writes out text in the same format as the daily and weekly reports. I've been on the app store for about 460 days selling in most countries daily, so my master.log files is 18MB. There is plenty of room for optimization, but this should help you for now.
(NOTE: I apologize if there are any typos...my version of AppSalesMobile has several other modifications, so I've tried to remove the parts that don't matter to everyone else)
At the bottom of RootViewController.m, I added another table entry for this:
else if ((row == 3) && (section == 2)) {
cell.imageView.image = [UIImage imageNamed:@"Settings2.png"];
cell.imageView.highlightedImage = [UIImage imageNamed:@"Settings2_Highlighted.png"];
cell.textLabel.text = NSLocalizedString(@"Master.log",nil);
cell.accessoryView = nil;
}
and in the last function in that file:
else if ((row == 3) && (section == 2)) {
[self WriteMasterLog];
}
which will call this function:
- (void)WriteMasterLog
{
NSString *path = [ NSString stringWithFormat:@"%@/%@", [[ReportManager sharedManager] originalReportsPath], @"master.log" ];
FILE *fp = fopen( [path cStringUsingEncoding:NSASCIIStringEncoding], "w" );
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"MM/dd/yyyy"];
NSSortDescriptor *dateSorter = [[[NSSortDescriptor alloc] initWithKey:@"date" ascending:YES] autorelease ];
NSArray *sortedDays = [[[ReportManager sharedManager].days allValues] sortedArrayUsingDescriptors:[NSArray arrayWithObject:dateSorter]];
// Version
fprintf( fp, "Version 01\n" );
//======//
// Days //
//======//
int nDaysExported = 0;
int nNumDays = [ReportManager sharedManager].days.count;
for ( Day *d in [sortedDays objectEnumerator] )
{
// Use our own autorelease pool inside this for loop
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSLog( @"Exporting day %d of %d\n", nDaysExported++, nNumDays );
NSString *dateString = [dateFormatter stringFromDate:d.date];
// Count number of entries for this day
int nNumEntries = 0;
for ( Country *c in [ d.countries allValues ] )
{
nNumEntries += c.entries.count;
}
fprintf( fp, "entries %d\n", nNumEntries );
fprintf( fp, "This line is ignored\n" );
// Loop over all entries in all countries and output one line of text per entry
for ( Country *c in [d.countries allValues] )
{
for ( Entry *e in c.entries )
{
NSString *productIdentifier = e.productIdentifier;
// This can be null for reports downloaded with an older version of ApSalesMobile!
if ( productIdentifier == nil )
{
productIdentifier = @"000000000";
}
fprintf( fp, " \t \t \t \t \t \t%s\t \t%d\t%d\t%.2f\t%s\t%s\t \t%s\t%s\t \t \t \t%s\t \t \t \n",
[ e.productName cStringUsingEncoding:NSASCIIStringEncoding ],
e.transactionType,
e.units,
e.royalties,
[ dateString cStringUsingEncoding:NSASCIIStringEncoding ],
[ dateString cStringUsingEncoding:NSASCIIStringEncoding ],
[ c.name cStringUsingEncoding:NSASCIIStringEncoding ],
[ e.currency cStringUsingEncoding:NSASCIIStringEncoding ],
[ productIdentifier cStringUsingEncoding:NSASCIIStringEncoding ] );
}
}
// Release our autorelease pool to free all memory allocated in this iteration of the loop
[pool release];
}
//=======//
// Weeks //
//=======//
NSDateFormatter *weekDayFormatter = [[NSDateFormatter alloc] init];
[weekDayFormatter setDateFormat:@"g"];
int nWeeksExported = 0;
for ( int iDay = 0; iDay < sortedDays.count; iDay++ )
{
// Use our own autorelease pool inside this for loop
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Get day
Day *d = [sortedDays objectAtIndex:iDay];
// Count total entries in all days this week and find first and last date
int nNumEntries = 0;
NSString *dayString = [weekDayFormatter stringFromDate:d.date];
int nDay = [dayString intValue] % 7;
NSString *fromDateString = [dateFormatter stringFromDate:d.date];
NSString *toDateString = [dateFormatter stringFromDate:d.date];
int i;
for ( i = nDay; i < 7; i++ )
{
if ( iDay+i-nDay > sortedDays.count-1 )
{
// Not enough days for this week
break;
}
Day *d = [sortedDays objectAtIndex:iDay+i-nDay];
NSString *dayString = [weekDayFormatter stringFromDate:d.date];
int nDay2 = [dayString intValue] % 7;
if ( ( i > nDay ) && ( nDay2 <= nDay ) ) // Skipped one or more days during the week
break;
for ( Country *c in [ d.countries allValues ] )
{
nNumEntries += c.entries.count;
}
if ( i > nDay )
{
toDateString = [dateFormatter stringFromDate:d.date];
}
}
if ( ( i < 7 ) && ( iDay+i-nDay > sortedDays.count-1 ) )
{
// Not enough days for this week, so stop looking for more weeks
break;
}
NSLog( @"Exporting week with %d days and %d entries (Day = %d) %@-%@\n", i, nNumEntries, nDay, fromDateString, toDateString );
fprintf( fp, "entries %d\n", nNumEntries );
fprintf( fp, "This line is ignored\n" );
// Loop over all entries in all countries and output one line of text per entry
int iDayOriginal = iDay;
for ( int i = nDay; i < 7; i++ )
{
// Use our own autorelease pool inside this for loop
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Get day
Day *d = [sortedDays objectAtIndex:iDayOriginal+i-nDay];
NSString *dayString = [weekDayFormatter stringFromDate:d.date];
int nDay2 = [dayString intValue] % 7;
if ( ( i > nDay ) && ( nDay2 <= nDay ) ) // Skipped one or more days during the week
break;
for ( Country *c in [d.countries allValues] )
{
for ( Entry *e in c.entries )
{
NSString *productIdentifier = e.productIdentifier;
// This can be null for reports downloaded with an older version of ApSalesMobile!
if ( productIdentifier == nil )
{
productIdentifier = @"000000000";
}
fprintf( fp, " \t \t \t \t \t \t%s\t \t%d\t%d\t%.2f\t%s\t%s\t \t%s\t%s\t \t \t \t%s\t \t \t \n",
[ e.productName cStringUsingEncoding:NSASCIIStringEncoding ],
e.transactionType,
e.units,
e.royalties,
[ fromDateString cStringUsingEncoding:NSASCIIStringEncoding ],
[ toDateString cStringUsingEncoding:NSASCIIStringEncoding ],
[ c.name cStringUsingEncoding:NSASCIIStringEncoding ],
[ e.currency cStringUsingEncoding:NSASCIIStringEncoding ],
[ productIdentifier cStringUsingEncoding:NSASCIIStringEncoding ] );
}
}
// Release our autorelease pool to free all memory allocated in this iteration of the loop
[pool release];
// Increment main counter
if ( i > nDay ) // don't increment the first time through since the outer loop does
iDay++;
}
nWeeksExported++;
// Release our autorelease pool to free all memory allocated in this iteration of the loop
[pool release];
}
NSLog( @"Calling fclose\n" );
fclose( fp );
NSLog( @"Done exporting\n" );
}
In ImportExportViewController.m, modify (void)fileUploaded to have this else if:
else if ([[[filename pathExtension] lowercaseString] isEqual:@"log"])
{
[[ProgressHUD sharedHUD] setText:NSLocalizedString(@"Importing...",nil)];
[[ProgressHUD sharedHUD] show];
[self performSelector:@selector(ImportMasterLogFile:) withObject:fullPath afterDelay:0.0];
}
Which will call this function:
- (void)ImportMasterLogFile:(NSString *)fullPath
{
NSAutoreleasePool *functionPool = [[NSAutoreleasePool alloc] init];
int importedWeeks = 0;
int importedDays = 0;
NSData *fileData = [[NSData alloc] initWithContentsOfFile:fullPath ];
if ( fileData != nil )
{
NSString *fileAsString = [ [ NSString alloc ] initWithData:fileData encoding:NSASCIIStringEncoding ];
[fileData release];
if ( fileAsString != nil )
{
NSScanner *scanner = [[NSScanner alloc] initWithString:fileAsString ];
[fileAsString release];
if ( scanner != nil )
{
int nVersion = 0;
[ scanner scanString:@"Version " intoString:NULL ];
[ scanner scanInt:&nVersion ];
// For each day
while ( 1 )
{
// Use our own autorelease pool inside this for loop
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
// Get num entries for this day
int nEntries = 0;
if ( [ scanner scanString:@"entries " intoString:NULL ] == NO )
{
// No more days
break;
}
[ scanner scanInt:&nEntries ];
// Read in all entries
NSString *allEntriesForToday = nil;
[ scanner scanUpToString:@"entries " intoString:&allEntriesForToday ];
// Create a Day object with this fake file
if ( allEntriesForToday != nil )
{
Day *report = [[Day alloc] initWithCSV:allEntriesForToday];
if (!report || !report.date)
{
NSLog(@"Invalid report file: %@", fullPath);
}
else
{
if (report.isWeek)
{
importedWeeks++;
NSLog(@"Imported week %i", importedWeeks);
}
else
{
importedDays++;
NSLog(@"Imported day %i", importedDays);
}
[[ReportManager sharedManager] importReport:report];
}
[report release];
}
// Release our autorelease pool to free all memory allocated in this iteration of the loop
[pool release];
} // End for each day
[scanner release];
}
}
}
if (importedDays == 0 && importedWeeks == 0)
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Error" message:NSLocalizedString(@"No valid report files were found in the master log you uploaded.",nil) delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil] autorelease];
[alert show];
}
else
{
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"" message:[NSString stringWithFormat:NSLocalizedString(@"Successfully imported %i daily and %i weekly reports.",nil), importedDays, importedWeeks] delegate:nil cancelButtonTitle:NSLocalizedString(@"OK",nil) otherButtonTitles:nil] autorelease];
[alert show];
}
[functionPool release];
[[ReportManager sharedManager] saveData];
[[NSNotificationCenter defaultCenter] postNotificationName:ReportManagerDownloadedDailyReportsNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:ReportManagerDownloadedWeeklyReportsNotification object:self];
[[NSNotificationCenter defaultCenter] postNotificationName:ReportManagerRefreshTotalsNotification object:self];
[[ProgressHUD sharedHUD] hide];
}
from appsales-mobile.
Thank you very much
from appsales-mobile.
One thing I should mention...when I updated to the latest version of AppSalesMobile, my weekly reports were corrupted and I lost all details of my weekly reports. So this export code generates fake weekly reports based on the daily reports you have. If you want to export your actual weekly reports, the code shouldn't be difficult to modify to do so.
from appsales-mobile.
import/export feature has existed for a few months, and this bug should be closed
from appsales-mobile.
I must have missed that. Is there code for outputting all sales numbers into a single exportable text file now like the code above?
from appsales-mobile.
It can import/export the raw iTC reports, which are in CSV format. You could merge all the reports using any spreadsheet program, or hack some simple code together (but AppSales doesn't include any functionality like that)
from appsales-mobile.
That's the problem, though. Many of us don't have the .gz files from most of the last year and a half...we only have the data that is held hostage on our phone :) The code above allows us to get at all of that data and allows me to backup all of my sales numbers in my perforce server in a single text file. Additionally, if we want to export all of the data to sync a new device, it's much more convenient to not have to deal with 500+ .gz/.txt files (most of which I don't even have).
from appsales-mobile.
Related Issues (20)
- fiscal months not handled for 2016 and + HOT 7
- Display wrong figure on monthly report HOT 2
- iOS 10 - App event doesn't Open HOT 2
- Report not Load
- App is Not Working Now - iOS 10.1 HOT 7
- Doesn't support 64-bit HOT 1
- The Autoingestion tool is no longer available HOT 1
- Reports from Nov 20 to Jan 2017 are displaying under Fiscal Month December 2016 HOT 1
- Reporter auth moving to tokens
- Can not use for several days HOT 7
- NSURLConnection finished with error - code -1022 HOT 4
- Can not Load Reports from last 15 days HOT 2
- Lots of $NaN in Sales
- Broken again - Downloaded report has incorrect date, ignoring HOT 11
- crash "export reports"
- Can't generate CSRF token
- pythonista
- accept
- ok
- https://www.instagram.com/ismail.ozcetin.33?igsh=OHZ1ZHRmY21rMTVl&utm_source=qr
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from appsales-mobile.