Code Monkey home page Code Monkey logo

Comments (8)

ivanguajana avatar ivanguajana commented on August 28, 2024

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.

blackfrog avatar blackfrog commented on August 28, 2024

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.

ivanguajana avatar ivanguajana commented on August 28, 2024

Thank you very much

from appsales-mobile.

blackfrog avatar blackfrog commented on August 28, 2024

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.

 avatar commented on August 28, 2024

import/export feature has existed for a few months, and this bug should be closed

from appsales-mobile.

blackfrog avatar blackfrog commented on August 28, 2024

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.

 avatar commented on August 28, 2024

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.

blackfrog avatar blackfrog commented on August 28, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.