API-INSEE-Sirene

 view release on metacpan or  search on metacpan

lib/API/INSEE/Sirene.pm  view on Meta::CPAN

        denominationUsuelle2UniteLegale denominationUsuelle3UniteLegale changementDenominationUsuelleUniteLegale
        categorieJuridiqueUniteLegale changementCategorieJuridiqueUniteLegale activitePrincipaleUniteLegale
        nomenclatureActivitePrincipaleUniteLegale changementActivitePrincipaleUniteLegale nicSiegeUniteLegale
        changementNicSiegeUniteLegale economieSocialeSolidaireUniteLegale changementEconomieSocialeSolidaireUniteLegale
        caractereEmployeurUniteLegale changementCaractereEmployeurUniteLegale
    / ],
    siret => [ qw/
        etatAdministratifEtablissement changementEtatAdministratifEtablissement
        enseigne1Etablissement enseigne2Etablissement enseigne3Etablissement changementEnseigneEtablissement
        denominationUsuelleEtablissement changementDenominationUsuelleEtablissement
        activitePrincipaleEtablissement nomenclatureActivitePrincipaleEtablissement changementActivitePrincipaleEtablissement
        caractereEmployeurEtablissement changementCaractereEmployeurEtablissement
    / ],
};

my $useful_fields_legal_unit = [
    qw/
        siren
        dateCreationUniteLegale
        sigleUniteLegale
        categorieEntreprise
        denominationUniteLegale denominationUsuelle1UniteLegale nomUniteLegale
        categorieJuridiqueUniteLegale
        activitePrincipaleUniteLegale nomenclatureActivitePrincipaleUniteLegale
        nicSiegeUniteLegale
    /
];

my $useful_fields_establishment = [
    qw/
        siren siret
        denominationUsuelleEtablissement denominationUniteLegale denominationUsuelle1UniteLegale nomUniteLegale
        activitePrincipaleUniteLegale
        numeroVoieEtablissement typeVoieEtablissement libelleVoieEtablissement
        codePostalEtablissement libelleCommuneEtablissement
    /
];

my $useful_fields_aliases = {
    nicSiege                        => 'nicSiegeUniteLegale',
    nom                             => [ 'denominationUniteLegale', 'nomUniteLegale' ],
    dateCreation                    => 'dateCreationUniteLegale',
    sigle                           => 'sigleUniteLegale',
    categorieJuridique              => 'categorieJuridiqueUniteLegale',
    nomenclatureActivitePrincipale  => 'nomenclatureActivitePrincipaleUniteLegale',
    activitePrincipale              => 'activitePrincipaleUniteLegale',
    numvoie                         => 'numeroVoieEtablissement',
    typevoie                        => 'typeVoieEtablissement',
    nomvoie                         => 'libelleVoieEtablissement',
    codePostal                      => 'codePostalEtablissement',
    nomCommune                      => 'libelleCommuneEtablissement',
    adresseComplete                 => [
                                        'numeroVoieEtablissement',
                                        'typeVoieEtablissement', 'libelleVoieEtablissement',
                                        'codePostalEtablissement', 'libelleCommuneEtablissement'
                                    ],
};

sub new {
    my $class = shift;
    my ($credentials, $timeout, $max_results, $proxy) = @_;

    my $self = bless {
        credentials      => $credentials,
        user_agent       => undef,
        token_expiration => undef,
        max_results      => undef,
        debug_mode       => 0,
        current_endpoint => undef,
    }, $class;

    $self->_initUserAgent();
    $self->setProxy($proxy);
    $self->setMaxResults($max_results);
    $self->setTimeout($timeout);

    return $self;
}

sub setCredentials {
    my ($self, $credentials) = @_;

    $self->{'credentials'} = $credentials;
}

sub setMaxResults {
    my ($self, $max_results) = @_;

    $max_results //= DEFAULT_MAX_RESULTS;
    $self->{'max_results'} = $max_results > HARD_MAX_RESULTS ? HARD_MAX_RESULTS : $max_results;
}

sub setDebugMode {
    my ($self, $debug_value) = @_;

    $self->{'debug_mode'} = $debug_value;
}

sub setProxy {
    my ($self, $proxy) = @_;

    defined $proxy ? $self->{'user_agent'}->proxy([ 'http', 'https' ], $proxy) : $self->{'user_agent'}->env_proxy;
}

sub setTimeout {
    my ($self, $timeout) = @_;

    $timeout //= DEFAULT_TIMEOUT;
    $self->{'user_agent'}->timeout($timeout);
}

sub setCurrentEndpoint {
    my ($self, $endpoint) = @_;

    $self->{'current_endpoint'} = $endpoint;
}

sub _dumpRequest {
    my ($self, $request, $response) = @_;

    my $dump = sprintf "Sent request:\n%s\n", $request->as_string;
    $dump .= sprintf "Received response:\n%s\n", $response->as_string if defined $response;

    return $dump;
}

sub _initUserAgent {
    my $self = shift;

    $self->{'user_agent'} = LWP::UserAgent->new(protocols_allowed => [ 'http', 'https' ]);

    $self->{'user_agent'}->agent("Perl API::INSEE::Sirene V$VERSION");
    $self->{'user_agent'}->default_header('Accept' => 'application/json');
}

sub _getToken {
    my $self = shift;

    croak 'Please provide your credentials.' if !defined $self->{'credentials'};

    my $request = POST API_AUTH_URL,
        Authorization => "Basic $self->{'credentials'}",
        Content       => [ grant_type => 'client_credentials' ];

    my $response = $self->{'user_agent'}->request($request);
    my $json_obj;

    if ($response->content_type =~ m/^application\/json/) {
        $json_obj = decode_json($response->content);
    }
    else {
        return 1, $self->_dumpRequest($request, $response); # the API may return xml intead of json...
    }

    switch ($response->code) {
        case HTTP_OK {
            $self->{'token_expiration'} = time + $json_obj->{'expires_in'};
            $self->{'user_agent'}->default_header( Authorization => "Bearer $json_obj->{'access_token'}" );
            return 0;
        }
        case HTTP_UNAUTHORIZED { # wrong credentials
            return 1 , $json_obj->{'error_description'};
        }
        else { # oh dear we are in trouble
            return 1, $self->_dumpRequest($request, $response);
        }
    }
}

sub _sendRequest {
    my ($self, $parameters) = @_;

    my $request;
    if (!exists $parameters->{'q'}) {
        my @url_parameters;

        foreach my $key (keys %{ $parameters }) {
            push @url_parameters, join '=', $key, $parameters->{$key};
        }

        my $endpoint = join '?', $self->{'current_endpoint'}, join '&', @url_parameters;
        $request = GET join '/', API_BASE_URL, $endpoint;
    }
    else {
        $request = POST join('/', API_BASE_URL, $self->{'current_endpoint'}),
            Content => [ %{ $parameters } ];
    }

    if ($self->{'debug_mode'}) { # Requests will not be sent in debug mode
        return 0, $self->_dumpRequest($request);
    }

    if (!defined $self->{'token_expiration'} || $self->{'token_expiration'} < time) {
        my ($err, $msg) = $self->_getToken();
        croak $msg if $err;
    }

    my $response = $self->{'user_agent'}->request($request);

    switch ($response->code) {
        case [ HTTP_OK, HTTP_NOT_FOUND ] {
            return 0, $response->content;
        }
        case HTTP_MOVED_PERMANENTLY { # duplicated legal unit/ establishment
            return 1, sprintf "%s\n%s", $response->message, $response->header('Location');
        }
        case [
            HTTP_REQUEST_URI_TOO_LARGE, HTTP_TOO_MANY_REQUESTS,
            HTTP_UNAUTHORIZED, HTTP_FORBIDDEN,
            HTTP_SERVICE_UNAVAILABLE
        ] {
# There is no syntax error in request, the http message should be sufficient to understand the problem
            return 1, $response->message;
        }
        else { # case HTTP_BAD_REQUEST || HTTP_INTERNAL_SERVER_ERROR
            return 1, $self->_dumpRequest($request, $response);
        }
    }
}

sub _buildParameters {

lib/API/INSEE/Sirene.pm  view on Meta::CPAN

    return $self->searchByCustomCriteria($criteria, $desired_fields);
}

sub getLegalUnitsByName {
    my ($self, $name, $desired_fields) = @_;

    $self->setCurrentEndpoint('siren');
    my $criteria = $self->getCustomCriteria('denominationUniteLegale', $name);

    return $self->searchByCustomCriteria($criteria, $desired_fields);
}

sub getEstablishmentsByName {
    my ($self, $name, $desired_fields) = @_;

    $self->setCurrentEndpoint('siret');
    my $criteria = $self->getCustomCriteria('denominationUniteLegale', $name);

    return $self->searchByCustomCriteria($criteria, $desired_fields);
}

sub getLegalUnitsByUsualName {
    my ($self, $name, $desired_fields) = @_;


    $self->setCurrentEndpoint('siren');
    my $criteria = $self->getCustomCriteria('denominationUsuelle1UniteLegale', $name);

    return $self->searchByCustomCriteria($criteria, $desired_fields);
}

sub getEstablishmentsByUsualName {
    my ($self, $name, $desired_fields) = @_;

    $self->setCurrentEndpoint('siret');
    my $criteria = $self->getCustomCriteria('denominationUsuelle1UniteLegale', $name);

    return $self->searchByCustomCriteria($criteria, $desired_fields);
}

1;

__END__

=pod

=encoding utf8

=head1 NAME

API::INSEE::Sirene - An interface for the Sirene API of INSEE

=head1 VERSION

Version 4.04

=head1 SYNOPSIS

  use API::INSEE::Sirene;

  my $sirene = API::INSEE::Sirene->new('Y29uc3VtZXIta2V5OmNvbnN1bWVyLXNlY3JldA=='); # your base64 encoded credentials
  $sirene->setMaxResults(30);

  # Examples to get information about an establishment with SIRET number '12345678987654'
  $sirene->getEstablishmentBySIRET(12345678987654, 'all');

  # or
  my $fields_that_interest_me = ['numeroVoieEtablissement', 'typeVoieEtablissement', 'libelleVoieEtablissement',
                                 'codePostalEtablissement', 'libelleCommuneEtablissement'];
  $sirene->getEstablishmentBySIRET(12345678987654, $fields_that_interest_me);

  # or
  $sirene->getEstablishmentBySIRET(12345678987654, 'denominationUniteLegale');

  # or simply
  $sirene->getEstablishmentBySIRET(12345678987654);

  # you can also perform searches whith a partial SIREN/SIRET number using search functions:
  $sirene->searchEstablishmentBySIRET(1234567898);
  $sirene->searchLegalUnitBySIREN(123456);

=head1 DESCRIPTION

This module allows you to interact with the Sirene API of INSEE (Institut National de la Statistique et des Études Économiques) in France.

It contains a set of functions that can perform searches on INSEE's database to get some information about french companies like their SIREN number, company name, company headquarters address, etc.

The terms "enterprise", "legal unit" and "establishment" used in this documentation are defined at the INSEE website in the following pages:

=over 4

=item * B<Enterprise definition:>

L<< https://www.insee.fr/en/metadonnees/definition/c1496 >>

=item * B<Legal unit definition:>

L<< https://www.insee.fr/en/metadonnees/definition/c1044 >>

=item * B<Establishment definition:>

L<< https://www.insee.fr/en/metadonnees/definition/c1377 >>

=back

Here is the documentation with among others all fields names:

=over 4

=item *

L<< https://api.insee.fr/catalogue/site/themes/wso2/subthemes/insee/pages/item-info.jag?name=Sirene&version=V3&provider=insee >>

=back

B<Please note that this API is french so all fields names used in function calls are in french, including the aliases.>

This module has been tested with 3.9 INSEE API version.

=head1 DEPENDENCIES

lib/API/INSEE/Sirene.pm  view on Meta::CPAN


You can use this method to build more specific criteria:

  my $criteria1 = $sirene->getCustomCriteria('numeroVoieEtablissement', 42);

You can choose between three search modes: 'exact', 'begin' or 'approximate' match. Default is 'approximate'.

  my $criteria2 = $sirene->getCustomCriteria('libelleVoieEtablissement', 'avenue', undef, 'exact');

B<< Important: >> You must specify the endpoint to be reached B<< before >> calling the C<< getCustomCriteria >> method using C<< setCurrentEndpoint >>

  $sirene->setCurrentEndpoint('siret');

=head2 getEstablishmentsByName

Search all establishments matching the specified name. (denominationUniteLegale field)

=head2 getEstablishmentsBySIREN

Search all the establishments attached to a legal unit identified by a SIREN number.

=head2 getEstablishmentBySIRET

Search an establishment by its SIRET number.

=head2 getEstablishmentsByUsualName

Search all establishments matching the specified name. (denominationUsuelle1UniteLegale field)

=head2 getLegalUnitsByName

Search all legal units matching the specified name. (denominationUniteLegale field)

=head2 getLegalUnitsByUsualName

Search all legal units matching the specified name. (denominationUsuelle1UniteLegale field)

=head2 getLegalUnitBySIREN

Search a legal unit by its SIREN number.

=head2 searchByCustomCriteria

This method is used to perform a search with a custom criteria built using the C<< getCustomCriteria >> method.

Before using this method, you have to specify the targeted endpoint by calling the C<< setCurrentEndpoint >> method.

  my $final_criteria = "$criteria1 OR $criteria2";
  my ($err, $result) = $sirene->$sirene->searchByCustomCriteria($final_criteria);

=head2 searchEstablishmentBySIRET

Search all establishments which SIRET number is begining by the number given in parameter.

=head2 searchLegalUnitBySIREN

Search all legal units which SIREN number is begining by the number given in parameter.

=head2 setCredentials

You can set your credentials separately from the instantiation if you need to (but this must be done before any call to the search methods).

  $sirene->setCredentials('Y29uc3VtZXIta2V5OmNvbnN1bWVyLXNlY3JldA==');

=head2 setCurrentEndpoint

Used to specifie the reached API endpoint.

=head2 setDebugMode

Enables the debug mode. When enabled, all the requests built by the module are displayed instead of being sent.

  $sirene->setDebugMode(1);

=head2 setMaxResults

Used to override the B<< DEFAULT_MAX_RESULTS >> value to get more results, within the limit of B<< HARD_MAX_RESULTS >> value.

  $sirene->setMaxResults(30);

=head2 setProxy

You can define which proxy server must be used to send requests. The system's proxy settings are used by default.

  $sirene->setProxy('https://myproxy.com:1234');

=head2 setTimeout

Used to override the B<< DEFAULT_TIMEOUT >> value.

  $sirene->setTimeout(40);

=head1 PARAMETERS

All search methods take an optional C<< $desired_fields >> parameter that comes in three differents flavours:

  my $fields_that_interest_me = ['dateCreationUniteLegale', 'sigleUniteLegale'];
  my $response_json = $sirene->getLegalUnitBySIREN(123456789, $fields_that_interest_me);

  # or
  my $response_json = $sirene->getLegalUnitBySIREN(123456789, 'dateCreationUniteLegale');

  # or
  my $response_json = $sirene->getLegalUnitBySIREN(123456789, 'all');

When you don't specify any desired field, the module returns a selection of fields that are most likely to interest you. (see C<$useful_fields_legal_unit> and C<$useful_fields_establishment> in source code to find out which ones)

If you want all fields, you have to specify it explicitly by passing the value 'all' as parameter.

=head1 RETURN VALUES

Each method returns a list of two elements: a return code, which is 0 in case of success, or something else in case of failure; and the result of the request (some json or an error message). In case of problem when calling API (malformed request for ...

The module may launch a croak if the crendentials are not initialized or if the SIREN/SIRET numbers are not given in a correct format.

=head1 ALIAS

Some fields have more user-friendly aliases:

  my $useful_fields_aliases = {
    nicSiege                        => 'nicSiegeUniteLegale',



( run in 0.253 second using v1.01-cache-2.11-cpan-00829025b61 )