package RPS::Import::AWAL::v5;

use strict;
use warnings;

use Date::Calc qw(Decode_Month Days_in_Month);

use lib '/app/tools/rps/lib';
use RPS::Import::ServiceMap;

use parent ( 'RPS::Import::MapFaceBase', 'RPS::Import::ImporterMixed');


sub physical { 2 }

sub _fieldMapExtended {
    {
        mixed => {
            option1 => {
                labelName       => 'E',
                serviceID       => 'D',
                countryCode     => 'C',
                dateBegin       => 'B',
                dateEnd         => 'B',
                productType     => 'P',
                formatType      => 'P',
                clientProductID => 'I',
                artistName      => 'F',
                upc             => 'J',
                albumName       => 'G',
                isrc            => 'N',
                trackName       => 'L',
                units           => 'R',
                currencyCode    => 'W',
                wholesalePrice  => 'Y',
                mediaType       => 'P',
                grossRevenue    => 'U',
            },
        },
    };
}

sub _unverifiedFieldMapExtended {
    {
        mixed => {
            option1 => {
                _netUnits                    => 'R',
                _netShareAccountCurrency     => 'X',
                _mechanicalDeduction         => 'AA',
                _mechanicalDeductionAdminFee => 'AB',
            },
        }
    };
}

sub _headerIdentifierExtended {
    {
        mixed => {
            option1 => { upc => 'DISPLAY UPC' }
        },
    };
}

my %typeMapping = (
    'subscription audio streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'cloud match units' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad-supported audio streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'mid-tier subscription audio streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'fraudulent streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'non-interactive radio' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'download tracks' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_DOWNLOAD,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription video streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'short-form video user generated revenue' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'ad-supported video streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'download albums' => {
        product_type => RPS::File::Sale::TYPE_ALBUM,
        format_type => RPS::File::Sale::FORMAT_DOWNLOAD,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad-supported video streams via app' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'video download purchases' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_DOWNLOAD,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'fitness subscription audio streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'tethered downloads' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_TETHERED,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad-supported video streaming (direct - over rate card)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'ad-supported video streaming (direct - at rate card)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'dj mix streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'internet radio and webcasting' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'tv broadcast' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'public performance' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'unidentified public performance and broadcast' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'radio broadcast' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'unidentified private copying' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'satellite radio' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'rental & lending' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'downloaded ringtones' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_RINGTONE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'streaming bonus' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'spatial subscription audio streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'unqualified audio streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'short functional noise audio streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'fraudulent stream penalties' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad supported audio streams from ugc' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad supported audio streams from art track videos' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription audio streams from ugc' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription audio streams from art track videos' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription streams from partnered channels (audio only mode)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription streams from ugc (audio only mode)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad supported video streams from partnered channels' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'ad supported video streams from ugc' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'subscription video streams from partnered channels' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'subscription video streams from ugc' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'paid features (super chat purchases)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'paid features (channel membership gifting)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'paid features (memberships)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'paid features (super stickers)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'paid features (brandconnect)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'paid features (super thanks)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'physical sales' => {
        product_type => RPS::File::Sale::TYPE_CD,
        media_type   => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'music dubbing' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_EPHEMERAL,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ephemeral' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_EPHEMERAL,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription audio streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad-supported video streams via app' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'tethered downloads' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_TETHERED,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'performance rights' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'internet radio and webcasting' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'radio broadcast' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'tv broadcast' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'rental & lending' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'public performance' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'unidentified private copying' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'satellite radio' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'exclusive rights' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'dj mix streams' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'cable radio' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'sync revenue' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_SYNC,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'private copying - audio' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'unidentified public performance and broadcast' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_PERFORMANCE,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad-supported video streaming (direct - at rate card)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'ad supported audio streams from art track videos' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription audio streams from art track videos' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription audio streams from ugc' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad supported audio streams from ugc' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription video streams from ugc' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'subscription streams from ugc (audio only mode)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad supported video streams from ugc' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'subscription streams from partnered channels (audio only mode)' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ad supported video streams from partnered channels' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'subscription video streams from partnered channels' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'making available / streaming' => {
        product_type => RPS::File::Sale::TYPE_TRACK,
        format_type => RPS::File::Sale::FORMAT_STREAM,
        media_type => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },

);

sub _getMapping {
    my $self = shift;

    return \%typeMapping;
}

sub channel    { RPS::File::Sale::CHANNEL_RETAIL }
sub priceLevel { RPS::File::Sale::PLEVEL_UNKNOWN }

sub serviceID {
    my $self = shift;

    my $service   = lc( $self->_getByFieldName('serviceID') || '' );
    my $serviceID = $self->getServiceID($service) || $RPS::Import::ServiceMap::SERVICE_ALIASES{$service};
    return $serviceID if $serviceID;

    return $self->handleError( "Unknown service: '$service'", RPS::DB::Item::SaleImportError::kErrorService );
}

sub countryCode {
    my $self = shift;

    my $country = $self->_getByFieldName('countryCode') || '';

    return 'TW' if $country =~ /^Taiwan/i;
    return 'TZ' if $country =~ /^Tanzania/i;
    return 'PS' if $country =~ /^Palestinian/i;
    return 'VE' if $country =~ /^Venezuela/i;
    return 'CD' if $country =~ /^Congo/i;
    return 'LA' if $country =~ /^Laos/i;
    return 'VG' if $country =~ /^Virgin Islands,\s?British/i;
    return 'VI' if $country =~ /^Virgin Islands,\s?U.S./i;
    return 'UM' if $country =~ /^Minor Outlying Islands, ?U.S/i;
    return 'KP' if $country =~ /^North Korea/i;
    return 'SH' if $country =~ /Saint Helena,\s?Ascension and Tristan da Cunha/i;
    return 'PN' if $country =~ /Pitcairn Islands/i;
    return 'TF' if $country =~ /French Southern and Antarctic Lands/i;

    my $oCountry = Common::Country->new( search => $country );
    return $oCountry->alpha2 if $oCountry;

    $self->fail("Unable to determine country code from '$country'");
}

sub dateBegin {
    my $self = shift;

    my $date = $self->_getByFieldName('dateBegin') || '';
    # YYYY-MM-DD
    if ( $date =~ /^(\d{4})[.\/-](\d{2})[.\/-](\d{2})$/i ) {
        return sprintf "%04d-%02d-%02d", $1, $2, 1;
    }
    # DD/MM/YYYY or MM/DD/YYYY
    if ( my ($d, $m, $y) = $date =~ /^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{2,4})$/ ) {
        $y = "20" . substr($y, -2);
        $m = $d if $m > 12;
        return sprintf "%04d-%02d-%02d", $y, $m, 1;
    }

    $self->fail("Unable to determine dateBegin from: '$date'");
}

sub dateEnd {
    my $self = shift;

    my $date = $self->_getByFieldName('dateEnd') || '';
    # YYYY-MM-DD
    if ( $date =~ /^(\d{4})[.\/-](\d{2})[.\/-](\d{2})$/i ) {
        return sprintf "%04d-%02d-%02d", $1, $2, Days_in_Month( $1, $2 );
    }
    # DD/MM/YYYY or MM/DD/YYYY
    if ( my ($d, $m, $y) = $date =~ /^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{2,4})$/ ) {
        $y = "20" . substr($y, -2);
        $m = $d if $m > 12;
        return sprintf "%04d-%02d-%02d", $y, $m, Days_in_Month($y, $m);
    }

    $self->fail("Unable to determine dateEnd from: '$date'");
}

sub productType {
    my $self = shift;
    my $type = lc( $self->_getByFieldName('productType') || '' );
    return $typeMapping{$type}{product_type} if exists $typeMapping{$type};

    return $self->fail( "Unable to determine product type from: '$type'" );
}

sub formatType {
    my $self = shift;

    # RSD-11462
    if ( $self->serviceID == Client::Service::DSP_SOUNDEXCHANGE ) {
        return RPS::File::Sale::FORMAT_NON_EPHEMERAL;
    }

    my $type = lc( $self->_getByFieldName('formatType') || '' );
    return $typeMapping{$type}{format_type} if exists $typeMapping{$type};

    return $self->fail( "Unable to determine format type from: '$type'" );
}

sub mediaType {
    my $self = shift;

    my $type = lc( $self->_getByFieldName('mediaType') || '' );
    return $typeMapping{$type}{media_type} if exists $typeMapping{$type};

    return RPS::DB::Item::MediaType::kMediaTypeAudio if ($type =~ /^physical/i);

    return $self->fail( "Unable to determine media type from: '$type'" );
}

# digital
sub price {
    my $self = shift;

    my $netShare         = $self->_getByFieldName('_netShareAccountCurrency')     || 0;
    my $mechDeduction    = $self->_getByFieldName('_mechanicalDeduction')         || 0;
    my $mechDeductionFee = $self->_getByFieldName('_mechanicalDeductionAdminFee') || 0;

    my $price = $netShare + $mechDeduction + $mechDeductionFee;
    return sprintf( "%.8f", abs($price));
}

sub unitPrice { abs shift->SUPER::unitPrice }
sub units {
    my $self = shift;

    my $units = $self->_getByFieldName('units') || 0;
    my $price = $self->_getByFieldName('price') || 0;

    if ( $price > 0 ) {
        $units = $units ? abs($units) : 1;
    } elsif ( $price < 0 ) {
       $units = $units ? -1 * abs($units) : -1;
    }

    return $units;
}

# physical
sub totalRevenue {
    my $self = shift;

    my $netShare         = $self->_getByFieldName('_netShareAccountCurrency')     || 0;
    my $mechDeduction    = $self->_getByFieldName('_mechanicalDeduction')         || 0;
    my $mechDeductionFee = $self->_getByFieldName('_mechanicalDeductionAdminFee') || 0;

    my $revenue = $netShare + $mechDeduction + $mechDeductionFee;
    return sprintf( "%.8f", $revenue);
}

sub netUnits       { $_[0]->_getByFieldName('_netUnits') || 0 }
sub sales          { $_[0]->netUnits     > 0 ? $_[0]->netUnits         : 0 }
sub salesRevenue   { $_[0]->totalRevenue > 0 ? $_[0]->totalRevenue     : 0 }
sub returns        { $_[0]->netUnits     < 0 ? abs $_[0]->netUnits     : 0 }
sub returnsRevenue { $_[0]->totalRevenue < 0 ? abs $_[0]->totalRevenue : 0 }

sub grossRevenue {
    my $self = shift;

    my $grossRevenue = $self->_getByFieldName('grossRevenue') || 0;

    return sprintf("%.8f", $grossRevenue);
}

sub _isValidSaleRecord {
    return ( $_[0]->_getByFieldName('trackName') || $_[0]->_getByFieldName('albumName') )
}

sub _mapFaceServiceID   { 'serviceID' }
sub _mapFaceProductType { }
sub _mapFaceFormatType  { }
sub _mapFaceMediaType   { }
sub _mapFaceCountryCode { }

1;
