Amazon-MWS

 view release on metacpan or  search on metacpan

META.json  view on Meta::CPAN

      },
      "configure" : {
         "requires" : {
            "ExtUtils::MakeMaker" : "0"
         }
      },
      "runtime" : {
         "requires" : {
            "Class::InsideOut" : "0",
            "DBI" : "0",
            "DateTime" : "0",
            "DateTime::Format::ISO8601" : "0",
            "Digest::HMAC_SHA1" : "0",
            "Digest::MD5" : "0",
            "Exception::Class" : "0",
            "Exporter" : "0",
            "HTTP::Request" : "0",
            "LWP::Protocol::https" : "0",
            "LWP::UserAgent" : "0",
            "MIME::Base64" : "0",
            "Moo" : "0",
            "MooX::Types::MooseLike" : "0",

META.yml  view on Meta::CPAN

  url: http://module-build.sourceforge.net/META-spec-v1.4.html
  version: '1.4'
name: Amazon-MWS
no_index:
  directory:
    - t
    - inc
requires:
  Class::InsideOut: '0'
  DBI: '0'
  DateTime: '0'
  DateTime::Format::ISO8601: '0'
  Digest::HMAC_SHA1: '0'
  Digest::MD5: '0'
  Exception::Class: '0'
  Exporter: '0'
  HTTP::Request: '0'
  LWP::Protocol::https: '0'
  LWP::UserAgent: '0'
  MIME::Base64: '0'
  Moo: '0'
  MooX::Types::MooseLike: '0'

Makefile.PL  view on Meta::CPAN

        'DBD::SQLite' => 0,
    },
    PREREQ_PM => {
        'URI'            => 0, 
        'URI::Escape'    => 0,
        'HTTP::Request'  => 0,
        'LWP::UserAgent' => 0,
        'LWP::Protocol::https' => 0,
        'XML::Simple'    => 0,

        'DateTime'                  => 0,
        'DateTime::Format::ISO8601' => 0,

        'Readonly'         => 0,
        'Class::InsideOut' => 0,
        'Exception::Class' => 0,
        'Exporter'         => 0,

        'MIME::Base64'      => 0,
        'Digest::MD5'       => 0,
        'Digest::HMAC_SHA1' => 0,

        'namespace::clean' => 0,
        'Moo' => 0,
        'MooX::Types::MooseLike' => 0,
        'DBI' => 0,
        'DateTime' => 0,
        'SQL::Abstract' => 0,
        'Try::Tiny' => 0,
        'Path::Tiny' => 0,
        'XML::Compile::Schema' => 1.46,
        'DateTime::Format::ISO8601' => 0,
        'XML::LibXML::Simple' => 0,
    },
    dist  => { COMPRESS => 'gzip -9f', SUFFIX => 'gz', },
    clean => { FILES => 'Amazon-MWS-*' },
    META_MERGE => {
        resources => {
            repository => 'https://github.com/interchange/Amazon-MWS',
            bugtracker => 'https://github.com/interchange/Amazon-MWS/issues',
            IRC => 'irc://irc.freenode.net/#interchange',
        },

examples/request-FBA-fulfillment-report.pl  view on Meta::CPAN

# Initiate FBA fulfillment report generation

use strict;

use Amazon::MWS::Client;
use DateTime;

my $mws = Amazon::MWS::Client->new(access_key_id=>"XXX",
                                   secret_key => "YYY",
                                   merchant_id => "ZZZ",
                                   marketplace_id => "VVV");

my $req = $mws->RequestReport(ReportType => '_GET_AMAZON_FULFILLED_SHIPMENTS_DATA_',
                              StartDate => DateTime->now->add(weeks => -1),
                              EndDate => DateTime->now);

if (my $req_id = $req->{ReportRequestInfo}->[0]->{ReportRequestId}) {
    open my $req, "> request.${req_id}";
    close $req;
}

lib/Amazon/MWS/FulfillmentInventory.pm  view on Meta::CPAN

   };

define_api_method ListInventorySupply =>
    raw_body => 1,
    version => '2010-10-01',
    service => "$fulfillment_service",
    parameters => {
        SellerSkus      => {
             type       => 'MemberList'
        },
        QueryStartDateTime      => { type => 'datetime' },
        ResponseGroup           => { type => 'List', values=>['Basic','Detailed'] }
    };

define_api_method ListInventorySupplyByNextToken =>
    raw_body => 1,
    version => '2010-10-01',
    service => "$fulfillment_service",
    parameters => {
        NextToken => {
            type     => 'string',

lib/Amazon/MWS/Routines.pm  view on Meta::CPAN

package Amazon::MWS::Routines;

use URI;
use DateTime;
use XML::Simple;
use URI::Escape;
use MIME::Base64;
use Digest::SHA;
use HTTP::Request;
use LWP::UserAgent;
use Digest::MD5 qw(md5_base64);
use Amazon::MWS::TypeMap qw(:all);
use Amazon::MWS::Exception;
use Data::Dumper;

lib/Amazon/MWS/Routines.pm  view on Meta::CPAN

        my $args = slurp_kwargs(@_);
        my $body = '';

        my %form = (
            Action           		=> $method_name,
            AWSAccessKeyId   		=> $self->{access_key_id},
            Merchant         		=> $self->{merchant_id},
            SellerId         		=> $self->{merchant_id},
            SignatureVersion 		=> 2,
            SignatureMethod  		=> 'HmacSHA256',
            Timestamp        		=> to_amazon('datetime', DateTime->now),
        );

        foreach my $name (keys %$params) {
            my $param = $params->{$name};
            unless (exists $args->{$name}) {
                Amazon::MWS::Exception::MissingArgument->throw(name => $name) if $param->{required};
                next;
            }

            my $type  = $param->{type};

lib/Amazon/MWS/Routines.pm  view on Meta::CPAN


    my $agent_string = "$appname/$version ($attr_str)";

    die 'No access key id' unless  $opts{access_key_id};
    die 'No secret key' unless $opts{secret_key};
    die 'No merchant id' unless $opts{merchant_id};
    die 'No marketplace id' unless $opts{marketplace_id};

    if ($opts{debug}) {
       open LOG, ">$opts{logfile}" or die "Cannot open logfile.";
       print LOG DateTime->now();
       print LOG "\nNew instance created. \n";
       print LOG Dumper(\%opts);
       close LOG; 
    }

 # https://github.com/interchange/Amazon-MWS/issues/9
 $opts{endpoint} ||= 'https://mws.amazonaws.com';
 # strip the trailing slashes
 $opts{endpoint} =~ s/\/+\z//;

lib/Amazon/MWS/TypeMap.pm  view on Meta::CPAN

package Amazon::MWS::TypeMap;

use warnings;
use strict;

use DateTime;
use DateTime::Format::ISO8601;

use Exporter qw(import);
our @EXPORT_OK = qw(from_amazon to_amazon);
our %EXPORT_TAGS = ( all => \@EXPORT_OK );

sub identity { shift }

my %from_map = (
    'string' => \&identity,
    'boolean' => sub { lc(shift) eq 'true' },
    'nonNegativeInteger' => \&identity, 
    'datetime' => sub {
        return DateTime::Format::ISO8601->parse_datetime(shift);
     },
);

sub from_amazon {
    my ($type, $value) = @_;
    return $from_map{$type}->($value);
}

my %to_map = (
    'string'   => \&identity,
    'boolean'  => sub { $_[0] ? 'true' : 'false' },
    'nonNegativeInteger' => sub {
        my $int = int(shift);
        $int = 1 unless $int > 0;
        return $int;
    },
    'datetime' => sub { 
	return DateTime::Format::ISO8601->parse_datetime(shift);
    },
);

sub to_amazon {
    my ($type, $value) = @_;
    return $to_map{$type}->($value);
}

1;

lib/Amazon/MWS/TypeMap.pm  view on Meta::CPAN


A plain perl string.

=head2 boolean

When sent by amazon, true is converted to 1 and false to the empty string.
When sent to amazon, any true value or false value will be properly converted.

=head2 datetime

Converted to and from DateTime objects.

=head1 AUTHOR

Paul Driver C<< frodwith@cpan.org >>

=head1 LICENCE AND COPYRIGHT

Copyright (c) 2009, Plain Black Corporation L<http://plainblack.com>.
All rights reserved

lib/Amazon/MWS/Uploader.pm  view on Meta::CPAN

use warnings;

use DBI;
use Amazon::MWS::XML::Feed;
use Amazon::MWS::XML::Order;
use Amazon::MWS::Client;
use Amazon::MWS::XML::Response::FeedSubmissionResult;
use Amazon::MWS::XML::Response::OrderReport;
use Data::Dumper;
use File::Spec;
use DateTime;
use SQL::Abstract;
use Try::Tiny;
use Path::Tiny;
use Scalar::Util qw/blessed/;
use XML::Compile::Schema;

use Moo;
use MooX::Types::MooseLike::Base qw(:all);
use namespace::clean;

lib/Amazon/MWS/Uploader.pm  view on Meta::CPAN

            $self->_exe_query($self->sqla->insert(amazon_mws_products => { %identifier, %data }));
        }
    }
}


sub prepare_feeds {
    my ($self, $task, $feeds) = @_;
    die "Missing task ($task) and feeds ($feeds)" unless $task && $feeds;
    return unless @$feeds; # nothing to do
    my $job_id = $task . "-" . DateTime->now->strftime('%F-%H-%M-%S');
    my $job_started_epoch = time();

    $self->_exe_query($self->sqla
                      ->insert(amazon_mws_jobs => {
                                                   amws_job_id => $job_id,
                                                   shop_id => $self->_unique_shop_id,
                                                   task => $task,
                                                   job_started_epoch => $job_started_epoch,
                                                  }));

lib/Amazon/MWS/Uploader.pm  view on Meta::CPAN

        $self->_print_or_warn_error("Job $job_id aborted!\n");
    }
    elsif ($success == $total) {
        $update = { success => 1 };
        print "Job successful!\n";
        # if we're here, all the products are fine, so mark them as
        # such if it's an upload job
        if ($row->{task} eq 'upload') {
            $self->_exe_query($self->sqla->update('amazon_mws_products',
                                                  { status => 'ok',
                                                    listed_date => DateTime->now,
                                                    listed => 1,
                                                  },
                                                  {
                                                   amws_job_id => $job_id,
                                                   shop_id => $self->_unique_shop_id,
                                                  }));
        }
    }
    else {
        print "Job still to be processed\n";

lib/Amazon/MWS/Uploader.pm  view on Meta::CPAN

    return Amazon::MWS::XML::Response::FeedSubmissionResult
      ->new(
            xml => $xml,
            xml_reader => $self->xml_reader,
           );
}

=head2 get_orders($from_date)

This is a self-contained method and doesn't require a product list.
The from_date must be a L<DateTime> object. If not provided, it will
the last week.

Returns a list of Amazon::MWS::XML::Order objects.

Beware that it's possible you get some items with 0 quantity, i.e.
single items cancelled. The application code needs to be prepared to
deal with such phantom items. You can check each order looping over
C<$order->items> checking for C<$item->quantity>.

=cut

sub get_orders {
    my ($self, $from_date) = @_;
    unless ($from_date) {
        $from_date = DateTime->now;
        $from_date->subtract(days => $self->order_days_range);
    }
    my @order_structs;
    my $res;
    try {
        $res = $self->client->ListOrders(
                                         MarketplaceId => [$self->marketplace_id],
                                         CreatedAfter  => $from_date,
                                        );
        push @order_structs, @{ $res->{Orders}->{Order} };

lib/Amazon/MWS/XML/Order.pm  view on Meta::CPAN

package Amazon::MWS::XML::Order;

use Amazon::MWS::XML::Address;
use Amazon::MWS::XML::OrderlineItem;

use strict;
use warnings;
use DateTime;
use DateTime::Format::ISO8601;
use Data::Dumper;

use Moo;
use MooX::Types::MooseLike::Base qw(:all);
use namespace::clean;

=head1 NAME

Amazon::MWS::XML::Order

lib/Amazon/MWS/XML/Order.pm  view on Meta::CPAN


=cut

sub items {
    my $self = shift;
    return @{ $self->items_ref };
}

=head2 order_date

Return a L<DateTime> object with th purchase date.

=cut

sub order_date {
    my ($self) = @_;
    return $self->_get_dt($self->order->{PurchaseDate});
}

sub _get_dt {
    my ($self, $date) = @_;
    return DateTime::Format::ISO8601->parse_datetime($date);
}

=head2 shipping_cost

The total shipping cost, built summing up the shipping cost of each
item.

=cut


lib/Amazon/MWS/XML/Product.pm  view on Meta::CPAN

Valid values are: AUD BRL CAD CNY DEFAULT EUR GBP INR JPY MXN USD.

Defaults to EUR.

=item sale_price

A sale price (optional)

=item sale_start

A DateTime object with the sale start date

=item sale_end

A DateTime object with the sale end date

=item images

An (optional) arrayref of image urls. The first will become the main
image, the other one will become the PT1, etc.

Please note that B<only http:// links> are allowed. If you pass https://
links, they will be rejected by Amazon.

=item children

lib/Amazon/MWS/XML/Product.pm  view on Meta::CPAN

    die "$price is negative" if $price < 0;
}


has sale_price => (is => 'ro',
                   isa => \&_validate_price);

has sale_start => (is => 'ro',
                   isa => sub {
                       die "Not a datetime"
                         unless $_[0]->isa('DateTime');
                   });

has sale_end => (is => 'ro',
                   isa => sub {
                       die "Not a datetime"
                         unless $_[0]->isa('DateTime');
                   });

has currency => (is => 'ro',
                 isa => sub {
                     my %currency = map { $_ => 1 } (qw/AUD BRL CAD CNY DEFAULT
                                                        EUR GBP INR JPY MXN USD/);
                     die "Not a valid currency" unless $currency{$_[0]};
                 },
                 default => sub { 'EUR' });

lib/Amazon/MWS/XML/Response/OrderReport.pm  view on Meta::CPAN

package Amazon::MWS::XML::Response::OrderReport;

use utf8;
use strict;
use warnings;
use DateTime;
use DateTime::Format::ISO8601;
use Data::Dumper;
use Amazon::MWS::XML::Response::OrderReport::Item;
use Amazon::MWS::XML::Address;
use Moo;
use MooX::Types::MooseLike::Base qw(HashRef ArrayRef Str Int);
use namespace::clean;

=head1 NAME

Amazon::MWS::XML::Response::OrderReport

lib/Amazon/MWS/XML/Response/OrderReport.pm  view on Meta::CPAN


=head2 amazon_order_number

=head2 email

The buyer email.

=head2 order_date

The date when the order processing was complete or when the order was
placed as a L<DateTime> object.

=head2 items

Return a list of L<Amazon::MWS::XML::Response::OrderReport::Item>,
which acts (more or less) like L<Amazon::MWS::XML::OrderlineItem>.

=cut

sub amazon_order_number {
    return shift->struct->{AmazonOrderID};

lib/Amazon/MWS/XML/Response/OrderReport.pm  view on Meta::CPAN


# OrderDate The date the order was placed
# OrderPostedDate The date the buyer's credit card was charged and order processing was completed

sub order_date {
    my $self = shift;
    my $struct = $self->struct;
    # maybe this would need a different method, but we don't know what
    # to do with it anyway.
    my $date = $struct->{OrderPostedDate} || $struct->{OrderDate};
    return DateTime::Format::ISO8601->parse_datetime($date);
}

sub items {
    return @{ shift->_items_ref };
}

=head2 as_ack_order_hashref

Return a structure suitable create an the acknowledge feed.

lib/Amazon/MWS/XML/ShippedOrder.pm  view on Meta::CPAN

package Amazon::MWS::XML::ShippedOrder;

use strict;
use warnings;
use DateTime;
use DateTime::Format::ISO8601;
use Moo;

=head1 NAME

Amazon::MWS::XML::ShippedOrder

=head1 DESCRIPTION

Class to validate and generate a shipping confirmation feed. While
L<Amazon::MWS::XML::Order> is meant to be used to parse the response,

lib/Amazon/MWS/XML/ShippedOrder.pm  view on Meta::CPAN


=head2 merchant_fulfillment_id

Optional and not used by Amazon

=head2 fulfillment_date

The date the item was actually shipped or picked up, depending on the
fulfillment method specified in the order.

A DateTime object is required. It will default to the current datetime
if not provided.

=head2 carrier

The "standard" carrier code or the carrier name. The module will try
to match it with the Amazon codes.

=head2 shipping_method

The shipping method for the carrier. Optional.

lib/Amazon/MWS/XML/ShippedOrder.pm  view on Meta::CPAN



=cut

has amazon_order_id => (is => 'ro');
has merchant_order_id => (is => 'ro');
has merchant_fulfillment_id => (is => 'ro');
has fulfillment_date => (is => 'ro',
                         isa => sub {
                             my $dt = $_[0];
                             die "Not a DateTime object"
                               unless ref($dt) && $dt->isa('DateTime');
                         },
                         default => sub { DateTime->now(time_zone => 'Europe/Berlin')},
                        );
has carrier => (is => 'ro', required => 1);
has shipping_method => (is => 'ro');
has shipping_tracking_number => (is => 'ro');
has items => (is => 'ro',
              isa => \&_validate_items,
              required => 1,
             );

sub _validate_items {

t/SubmitFeed.t  view on Meta::CPAN

use warnings;
use strict;

use Amazon::MWS::Client;
use Amazon::MWS::Enumeration::FeedType qw(:all);
use Amazon::MWS::Enumeration::FeedProcessingStatus qw(:all);
use Test::MockObject::Extends;
use Test::MockObject;
use HTTP::Response;
use Test::More tests => 4;
use DateTime;
use Data::Dumper;

my $client = Amazon::MWS::Client->new(
    access_key_id  => 'foo',
    secret_key     => 'bar',
    merchant_id    => 'baz',
    marketplace_id => 'goo',
);

my $agent = Test::MockObject->new->mock(

t/SubmitFeed.t  view on Meta::CPAN

</AmazonEnvelope>
FEED_CONTENT
);
};

diag Dumper($@) if $@;

is $response->{FeedProcessingStatus}, _SUBMITTED_;
is $response->{FeedSubmissionId}, '11223344';
is $response->{FeedType}, _POST_ORDER_FULFILLMENT_DATA_;
is $response->{SubmittedDate}, DateTime->new(
    year => 2011,
    month => 2,
    day => 8,
    hour => 9,
    minute => 49,
    second => 35
);

t/job-selection.t  view on Meta::CPAN

#!perl

use utf8;
use strict;
use warnings;
use Amazon::MWS::Uploader;
use Data::Dumper;
use Test::More;
use DateTime;
use DBI;

binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

my $feed_dir = 't/feeds';

if (-d 'schemas') {
    plan tests => 12;
}

t/order-reports.t  view on Meta::CPAN


ok(@orders == 2, "Got the orders");
my $count = 0;
foreach my $order (@orders) {
    $count++;
    ok ($order, "object ok");
    ok ($order->amazon_order_number, "Got order number")  and diag $order->amazon_order_number;
    ok ($order->struct, "struct ok");

    my $order_date = $order->order_date;
    ok($order_date->isa('DateTime'), "datetime object returned");
    foreach my $method (qw/name city zip country address_line region/) {
        ok ($order->shipping_address->$method, "shipping $method ok")
          and diag $order->shipping_address->$method;
        # only our example have a billing address
        if ($count == 1) {
            ok ($order->billing_address->$method, "billing $method ok")
              and diag $order->billing_address->$method;
        }
        else {
            ok (!$order->billing_address);

t/shipping-confirmation.t  view on Meta::CPAN

#!perl

use utf8;
use strict;
use warnings;
use Test::More;
use Amazon::MWS::XML::ShippedOrder;
use Amazon::MWS::Uploader;
use DateTime;


my $test_extended;
my $schema_dir = 'schemas';
if (-d $schema_dir) {
    plan tests => 5;
    $test_extended = 1;
}
else {
    plan tests => 2;
}

my %shipped = (
               # amazon_order_id => '12341234',
               merchant_order_id => '8888888',
               merchant_fulfillment_id => '666666', # optional
               fulfillment_date => DateTime->new(
                                                 year => 2014,
                                                 month => 11,
                                                 day => 14,
                                                 hour => 11,
                                                 minute => 11,
                                                 second => 0,
                                                 time_zone => 'Europe/Berlin',
                                                ),
               carrier => 'UPS',
               shipping_method => 'Second Day',

t/shipping-confirmation.t  view on Meta::CPAN

        <Quantity>2</Quantity>
      </Item>
    </OrderFulfillment>
  </Message>
</AmazonEnvelope>
XML

%shipped = (
            merchant_order_id => 1234567,
            merchant_fulfillment_id => 1234567,
            fulfillment_date => DateTime->new(year => 2002,
                                              month => 5,
                                              day => 1,
                                              hour => 15,
                                              minute => 36,
                                              second => 33,
                                              time_zone => '-08:00',
                                              ),
            carrier => 'UPS',
            shipping_method => 'Second Day',
            shipping_tracking_number => 1234567890,

t/uploader.t  view on Meta::CPAN

#!perl

use utf8;
use strict;
use warnings;
use Amazon::MWS::Uploader;
use Data::Dumper;
use Test::More;
use DateTime;

binmode STDOUT, ':utf8';
binmode STDERR, ':utf8';

my $feed_dir = 't/feeds';

if (-d 'schemas') {
    plan tests => 26;
}
else {

t/uploader.t  view on Meta::CPAN

    foreach my $code (qw/8001 8002 8003 8008/) {
        $uploader->_error_logger(warning => $code => "$code ć warn");
    }
    is (scalar(@warned), 2) or diag Dumper(\@warned);
    is_deeply(\@warned, [
                         "Invalid mode invalid for warning: 8001 ć warn (8001)\n",
                         "warning: 8002 ć warn (8002)\n",
                        ]);
}

my $now = DateTime->now;

my $old = $now->clone->subtract(hours => 2);

ok (!$uploader->job_timed_out({
                               task => 'order_ack',
                               job_started_epoch => $old->epoch,
                              }),
    "order_ack doesn't timeout in 2 hours since " . $old->ymd);

ok (!$uploader->job_timed_out({



( run in 0.506 second using v1.01-cache-2.11-cpan-05444aca049 )