API-Octopart
view release on metacpan or search on metacpan
lib/API/Octopart.pm view on Meta::CPAN
);
# Query part stock:
my %opts = (
currency => 'USD',
max_moq => 100,
min_qty => 10,
max_price => 4,
#mfg => 'Murata',
);
print Dumper $o->get_part_stock_detail('RC0805FR-0710KL', %opts);
print Dumper $o->get_part_stock_detail('GQM1555C2DR90BB01D', %opts);
=head1 METHODS
=over 4
=item * $o = API::Octopart->new(%opts) - Returns new Octopart object.
Object Options (%opt):
=over 4
=item * token => 'abcdefg-your-octopart-token-here',
This is your Octopart API token. You could do something like this to read the token from a file:
token => (sub { my $t = `cat ~/.octopart/token`; chomp $t; return $t})->(),
=item * include_specs => 1
If you have a PRO account then you can include product specs:
=item * cache => "$ENV{HOME}/.octopart/cache"
An optional (but recommended) cache directory to minimize requests to Octopart:
=item * cache_age => 3
The cache age (in days) before re-querying octopart. Defaults to 30 days.
=item * query_limit: die if too many API requests are made.
Defaults to no limit. I exhasted 20,000 queries very quickly due to a bug!
This might help with that, set to a reasonable limit while testing.
=item * ua_debug => 1
User Agent debugging. This is very verbose and provides API communication details.
=item * json_debug => 1
JSON response debugging. This is very verbose and dumps the Octopart response
in JSON.
=back
=cut
our %valid_opts = map { $_ => 1 } qw/token include_specs cache cache_age ua_debug query_limit json_debug/;
sub new
{
my ($class, %args) = @_;
foreach my $arg (keys %args)
{
die "invalid option: $arg => $args{$arg}" if !$valid_opts{$arg};
}
$args{api_queries} = 0;
$args{cache_age} //= 30;
die "An Octopart API token is required." if (!$args{token});
return bless(\%args, $class);
}
=item * $o->has_stock($part, %opts) - Returns the number of items in stock
$part: The model number of the part
%opts: Optional filters. No defaults are specified, it will return all unless limited.
=over 4
=item * min_qty => <n> - Minimum stock quantity, per seller.
If a sellerhas fewer than min_qty parts in stock then the seller will be excluded.
=item * max_moq => <n> - Maximum "minimum order quantity"
This is the max MOQ you will accept as being in
stock. For example, a 5000-part reel might be more
than you want for prototyping so set this to 10 or
100.
=item * seller => <regex> - Seller's name (regular expression)
This is a regular expression so something like
'Mouser|Digi-key' is valid.
=item * mfg => <regex> - Manufacturer name (regular expression)
Specifying the mfg name is useful if your part model
number is similar to those of other manufacturers.
=item * currency => <s> - eg, 'USD' for US dollars
Defaults to include all currencies
=back
=cut
sub has_stock
{
my ($self, $part, %opts) = @_;
my $parts = $self->get_part_stock_detail($part, %opts);
lib/API/Octopart.pm view on Meta::CPAN
"Basic Example" so you can easily lookup a specific part number. The has_stock()
and get_part_stock_detail() methods use this query internally.
=cut
sub query_part_detail
{
my ($self, $part) = @_;
# Specs require a pro account:
my $specs = '';
if ($self->{include_specs})
{
$specs = q(
specs {
units
value
display_value
attribute {
id
name
shortname
group
}
}
);
}
return $self->octo_query( qq(
query {
search(q: "$part", limit: 3) {
results {
part {
manufacturer {
name
}
mpn
$specs
# Brokers are non-authorized dealers. See: https://octopart.com/authorized
sellers(include_brokers: false) {
company {
name
}
offers {
click_url
inventory_level
prices {
price
currency
quantity
}
}
}
}
}
}
}
));
}
our %_valid_filter_opts = ( map { $_ => 1 } (qw/currency max_moq min_qty max_price mfg seller/) );
sub _parse_part_stock
{
my ($self, $resp, %opts) = @_;
foreach my $o (keys %opts)
{
die "invalid filter option: '$o'" if (!$_valid_filter_opts{$o});
}
my @results;
foreach my $r (@{ $resp->{data}{search}{results} })
{
$r = $r->{part};
my %part;
$part{mfg} = $r->{manufacturer}{name};
if (defined $r->{specs})
{
$part{specs} = {
# Try to map first by shortname, then by unit, then by value if
# the former are undefined:
map {
defined($_->{attribute}{shortname})
? ($_->{attribute}{shortname} => $_->{value} . "$_->{units}")
: (
$_->{units}
? ($_->{units} => $_->{value})
: ($_->{value} => 'true')
)
} @{ $r->{specs} }
},
}
# Seller stock and MOQ pricing:
my %ss;
foreach my $s (@{ $r->{sellers} })
{
foreach my $o (@{ $s->{offers} })
{
$ss{$s->{company}{name}}{stock} = $o->{inventory_level};
foreach my $p (@{ $o->{prices} })
{
next if (defined($opts{currency}) && $p->{currency} ne $opts{currency});
my $moq = $p->{quantity};
my $price = $p->{price};
$ss{$s->{company}{name}}{price_tier}{$p->{quantity}} = $price;
# Find the minimum order quantity and the MOQ price:
if (!defined($ss{$s->{company}{name}}{moq}) ||
$ss{$s->{company}{name}}{moq} > $moq)
{
$ss{$s->{company}{name}}{moq} = $moq;
$ss{$s->{company}{name}}{moq_price} = $price;
}
}
}
}
$part{sellers} = \%ss;
push @results, \%part;
}
# Delete sellers that do not meet the constraints and
# add matching results to @ret:
my @ret;
foreach my $r (@results)
{
next if (defined($opts{mfg}) && $r->{mfg} !~ /$opts{mfg}/i);
foreach my $s (keys %{ $r->{sellers} })
{
if (!defined($r->{sellers}{$s}{price_tier})
|| (defined($opts{min_qty}) && $r->{sellers}{$s}{stock} < $opts{min_qty})
|| (defined($opts{max_price}) && $r->{sellers}{$s}{moq_price} > $opts{max_price})
|| (defined($opts{max_moq}) && $r->{sellers}{$s}{moq} > $opts{max_moq}
|| defined($opts{seller}) && $s !~ /$opts{seller}/i)
)
{
delete $r->{sellers}{$s};
( run in 0.882 second using v1.01-cache-2.11-cpan-140bd7fdf52 )