package Net::DSLProvider::Enta;
use strict;
use warnings;
use HTML::Entities qw(encode_entities_numeric);
use base 'Net::DSLProvider';
use constant ENDPOINT => "https://partners.enta.net/";
use constant BOUNDARY => "abc123xyz890";
use constant REALM => "Entanet Partner Logon";
use LWP;
use HTTP::Cookies;
use XML::Simple;
use Time::Piece;
use Time::Seconds;
use Date::Holidays::EnglandWales;
# These are methods for which we have to pass Enta a block of XML as a file
# via POST rather than simply using GET with the parameters and the fields
# in the XML are case sensitive while they are not when using GET
my %enta_xml_methods = ( "ProductChange" => 1,
"ModifyLineFeatures" => 1, "UpdateADSLContact" => 1,
"CreateADSLOrder" => 1 );
my %entatype = ( "CreateADSLOrder" => "ADSLOrder",
"ModifyLineFeatures" => "ModifyLineFeatures",
"UpdateADSLContact" => "UpdateADSLContact",
"ProductChange" => "ProductChange" );
my %formats = (
ADSLChecker => { "PhoneNo" => "phone", "Version" => "4", "PostCode" => "text",
"MACcode" => "text" },
AdslAccount => { "Username" => "username", "Ref" => "ref", "Telephone" => "telephone" },
ProductChange => {
"ProductChange" => {
"Username" => "username", "Ref" => "ref", "Telephone" => "telephone",
"NewProduct" => {
"Family" => "family", "Cap" => "cap", "Speed" => "speed",
},
"Schedule" => "schedule",
},
},
ListConnections => { "liveorceased" => "text", "fields" => "text" },
CheckUsernameAvailable => { "Username" => "username" },
GetBTFault => { "day" => "text", "start" => "text", "end" => "text" },
GetAdslInstall => { "Username" => "text", "Ref" => "text" },
GetBTFeed => { "Days" => "counting" },
GetNotes => => { "Username" => "text", "Ref" => "text" },
LastRadiusLog => { "Username" => "text", "Ref" => "text" },
ConnectionHistory => { "Username" => "text", "Ref" => "text", "Telephone" => "phone",
"days" => "counting" },
GetInterleaving => { "Username" => "text", "Ref" => "text", "Telephone" => "phone" },
GetOpenADSLFaults => { "Username" => "text", "Ref" => "text", "Telephone" => "phone" },
RequestMAC => { "Username" => "text", "Ref" => "text", "Telephone" => "phone" },
UsageHistory => { "Username" => "username", "Ref" => "ref", "Telephone" => "telephone",
"StartTimeStamp" => "starttimestamp", "EndTimeStamp" => "endtimestamp",
"StartDateTime" => "startdatetime", "EndDateTime" => "enddatetime" },
UsageHistoryDetail => { "Username" => "text", "Ref" => "text", "Telephone" => "phone",
"startday" => "dd/mm/yyyy", "endday" => "dd/mm/yyyy", "day" => "dd/mm/yyyy" },
ADSLTopup => { "username" => "text", "ref" => "text", "telephone" => "phone" },
GetMaxReports => { "Username" => "text", "Ref" => "text", "Telephone" => "phone" },
CreateADSLOrder => {
ADSLAccount => {
"YourRef" => "client-ref", "Product" => "prod-id", "MAC" => "mac",
"Title" => "title", "FirstName" => "forename",
"Surname" => "surname", "CompanyName" => "company",
"Building" => "building", "Street" => "street", "Town" => "city",
"County" => "county", "Postcode" => "postcode",
"TelephoneDay" => "telephone", "TelephoneEvening" => "telephone",
"Fax" => "fax", "Email" => "email", "Telephone" => "cli",
"ProvisionDate" =>"crd", "NAT" => "allocation-size",
"Username" => "username", "Password" => "password",
"LineSpeed" => "linespeed", "OveruseMethod" => "topup",
"ISPName" => "losing-isp", "CareLevel" => "care-level",
"Interleave" => "max-interleaving", "ForceLowerSpeed" => "classic",
"BTProductSpeed" => "classic-speed", "Realm" => "realm",
"BaseDomain" => "realm", "ISDN" => "isdn",
"InitialCareLevelFee" => "iclfee",
"OngoingCareLevelFee" => "oclfee", "TagOnTheLine" => 'totl',
"MaxPAYGAmount" => "payg-limit", "AssignIPV6" => "ipv6"
},
CustomerRecord => {
"cCustomerID" => "customer-id", "cTitle" => "ctitle",
"cFirstName" => "cforename", "cSurname" => "csurname",
"cCompanyName" => "ccompany", "cBuilding" => "cbuilding",
"cStreet" => "cstreet", "cTown" => "ctown",
"cCounty" => "ccounty", "cPostcode" => "cpostcode",
"cTelephoneDay" => "ctelephone",
"cTelephoneEvening" => "ctelephone",
"cFax" => "cfax", "cEmail" => "cemail"
},
BillingAccount => {
"PurchaseOrderNumber" => "client-ref",
"BillingPeriod" => "billing-period",
"ContractTerm" => "contract-term",
"InitialPaymentMethod" => "initial-payment",
"OngoingPaymentMethod" => "ongoing-payment",
"PaymentMethod" => "payment-method"
}
},
ModifyLineFeatures => { "ADSLAccount" => {
"Ref" => "text", "Username" => "text", "Telephone" => "phone",
"LineFeatures" => {
"Interleaving" => "text", "StabilityOption" => "text",
"ElevatedBestEfforts" => "yesno", "ElevatedBestEffortsFee" => "text",
"MaintenanceCategory" => "counting", "MaintenanceCategoryFee" => "text"
}
}
},
CeaseADSLOrder => { "Username" => "username", "Ref" => "ref", "Telephone" => "telephone",
ceaseDate => 'ceasedate' },
ChangeInterleave => { "Username" => "text", "Ref" => "text", "Telephone" => "phone",
Interleave => "text" },
UpdateADSLContact => { "Ref" => "ref", "Username" => "username", Telephone => "telephone",
ContactDetails => { Email => "email", TelDay => "phone", TelEve => "phone" }
} );
sub _request_xml {
my ($self, $method, $args) = @_;
if ( $args->{cli} && ( ! $args->{Telephone} ) ) {
$args->{Telephone} = $args->{cli};
}
my $live = "Test";
$live = "Live" unless $self->testing;
my $xml = qq|<?xml version="1.0" encoding="UTF-8"?>\n<ResponseBlock Type="$live">\n|;
if ( $enta_xml_methods{$method} ) {
if ( $method eq 'CeaseADSLOrder' ) {
$xml .= qq|<Response Type="ADSLCease">\n<OperationResponse">\n|;
}
else {
$xml .= qq|<Response Type="| . $entatype{$method} . qq|">\n<OperationResponse Type="| . $entatype{$method} . qq|">\n|;
}
} else {
$xml .= qq|<OperationResponse Type="| . $entatype{$method} . qq|">\n|;
}
my $recurse;
$recurse = sub {
my ($format, $data) = @_;
while (my ($key, $contents) = each %$format) {
if (ref $contents eq "HASH") {
if ($key) {
if ( $key eq 'ProductChange' ) {
my $id = "Ref" if $args->{Ref};
$id = "Telephone" if $args->{Telephone};
$id = "Username" if $args->{Username};
$xml .= qq|<$key $id="|.$args->{$id}.qq|">\n|;
}
else {
$xml .= "\t<$key>\n";
}
}
$recurse->($contents, $data->{$key});
if ($key) {
$xml .= "</$key>\n";
}
} else {
$xml .= qq{\t\t<$key>}.encode_entities_numeric($args->{$key})."</$key>\n" if $args->{$key};
}
}
};
$recurse->($formats{$method}, $args);
if ( $enta_xml_methods{$method} ) {
$xml .= "</OperationResponse>\n</Response>\n</ResponseBlock>";
} else {
$xml .= "</OperationResponse>\n</ResponseBlock>";
}
return $xml;
}
sub _make_request {
my ($self, $method, $data) = @_;
my $ua = new LWP::UserAgent;
my ($req, $res, $body) = ();
$ua->cookie_jar({});
my $agent = __PACKAGE__ . '/0.1 ';
$ua->agent($agent . $ua->agent);
my $url = ENDPOINT . "xml/$method" . '.php';
$url = ENDPOINT . "xml-beta/$method" . '.php' if $method eq "UsageHistory";
$url = ENDPOINT . "xml/AdslProductChange" . '.php' if $method eq "ProductChange";
if ( $enta_xml_methods{$method} ) {
push @{$ua->requests_redirectable}, 'POST';
my $xml = $self->_request_xml($method, $data);
$body .= "--" . BOUNDARY . "\n";
$body .= "Content-Disposition: form-data; name=\"userfile\"; filename=\"XML.data\"\n";
$body .= "Content-Type: application/octet-stream\n\n";
$body .= $xml;
$body .= "\n";
$body .= "--" . BOUNDARY . "--\n";
$req = new HTTP::Request 'POST' => $url;
} else {
push @{$ua->requests_redirectable}, 'GET';
my ($key, $value);
$url .= '?';
$url .= "$key=$value&" while (($key, $value) = each (%$data));
$req = new HTTP::Request 'GET' => $url;
}
$req->authorization_basic(@{[$self->user]}, @{[$self->pass]});
$req->header( 'MIME_Version' => '1.0', 'Accept' => 'text/xml' );
if ( $enta_xml_methods{$method}) {
$req->header('Content-type' => 'multipart/form-data; type="text/xml"; boundary=' . BOUNDARY);
$req->header('Content-length' => length $body);
$req->content($body);
}
if ( $self->debug ) { use Data::Dumper; warn Dumper $req; }
$res = $ua->request($req);
if ( $self->debug ) { warn $res->content; }
die "Request for Enta method $method failed: " . $res->message if $res->is_error;
# Sometimes Enta doesn't return anything at all on success
return undef unless $res->content;
my $resp_o = XMLin($res->content, SuppressEmpty => 1);
if ($resp_o->{Response}->{Type} eq 'Error') { die $resp_o->{Response}->{OperationResponse}->{ErrorDescription}; };
my $recurse = undef;
$recurse = sub {
my $input = shift;
while ( my ($oldkey, $contents) = each %$input ) {
my $newkey = $oldkey;
$newkey =~ s/-/_/g;
$input->{$newkey} = $recurse->($contents), if ref $contents eq 'HASH';
if ( ref $contents eq "ARRAY" ) {
for my $r ( @{$contents} ) {
$recurse->($r);
}
}
$input->{$newkey} = $contents;
delete $input->{$oldkey} if $oldkey =~ /-/;
}
};
$recurse->($resp_o);
if ( $self->debug ) { use Data::Dumper; warn Dumper $resp_o; }
return $resp_o;
}
sub _convert_input {
my ($self, $method, $args) = @_;
die "convert_input called without method or args hashref" unless $method && ref $args eq 'HASH';
my $data = {};
$args->{'ref'} = delete $args->{"service-id"} if $args->{"service-id"};
$args->{telephone} = $args->{cli} if ((!$args->{telephone}) && $args->{cli});
my $recurse = undef;
$recurse = sub {
my ($format, $arg) = @_;
while (my ($key, $contents) = each %$format) {
if (ref $contents eq "HASH") {
$recurse->($contents, $arg->{$key});
}
else {
$data->{$key} = $args->{$contents} if $args->{$contents};
}
}
};
$recurse->($formats{$method}, $args);
return $data;
}
sub _serviceid {
my ( $self, $args ) = @_;
die "You must supply the service-id parameter" unless
( $args->{"ref"} || $args->{"username"} ||
$args->{"telephone"} || $args->{"service-id"} ||
$args->{"order-id"} ) ;
return { "Ref" => $args->{"service-id"} } if $args->{"service-id"};
return { "Ref" => $args->{"order-id"} } if $args->{"order-id"};
return { "Ref" => $args->{"ref"} } if $args->{"ref"};
return { "Username" => $args->{"username"} } if $args->{"username"};
return { "Telephone" => $args->{"telephone"} } if $args->{"telephone"};
}
=head2 services_available
$enta->services_available ( cli => "02072221122" );
Returns a hash showing line qualification data
=cut
sub services_available {
my ($self, %args) = @_;
my %details = $self->adslchecker( %args );
die "It is not possible to obtain information on your phone line"
unless $details{ErrorCode} eq "0";
if ( $details{FixedRate}->{RAG} eq "R" && $details{RateAdaptive}->{RAG} eq "R" ) {
die "It is not possible to provide any ADSL service on your line";
}
if ( $details{MAC} && ( $details{MAC}->{Valid} ne "Y" ) ) {
die $details{MAC}->{"ReasonCode"};
}
my $t = Time::Piece->new();
$t += ONE_WEEK;
while ( is_uk_holiday($t->ymd) || ($t->wday == 1 || $t->wday == 7) ) {
$t += ONE_DAY;
}
my %rv = ();
my $top = undef;
if ( $details{FixedRate}->{RAG} =~ /(R|A|G)/ &&
$details{RateAdaptive}->{RAG} =~ /^(A|G)$/ ) {
$rv{qualification}->{classic} = 512000;
}
if ( $details{FixedRate}->{RAG} =~ /(A|G)/ &&
$details{RateAdaptive}->{RAG} eq "G" ) {
$rv{qualification}->{classic} = 1024000;
}
if ( $details{FixedRate}->{RAG} eq "G" &&
$details{RateAdaptive}->{RAG} eq "G" ) {
$rv{qualification}->{classic} = 2048000;
}
$top = $rv{qualification}->{classic};
if ( $details{Max}->{RAG} ne "R" ) {
$rv{qualification}->{max} = $details{Max}->{Speed} * 1024;
$top = $rv{qualification}->{max};
}
if ( $details{WBC}->{RAG} && $details{WBC}->{RAG} ne "R" ) {
$rv{qualification}->{'2plus'} = $details{WBC}->{Speed} * 1024;
$top = $rv{qualification}->{'2plus'};
}
if ( $details{FullMsg} =~ /WBC FTTC Broadband where consumers have received downstream line speed of (.*)Mbps and upstream line speed of (.*)Mbps/g ) {
$rv{qualification}->{fttc} = {
down => $1 * 1024*1024,
up => $2 * 1024*1024
};
}
if ( $details{FullMsg} =~ /Your cabinet is planned to have WBC FTTC by (.*)(\d{4})\./s ) {
my $planned = $1;
my $year = $2;
my $nth = '(st|nd|rd|th)';
$planned =~ s/(\d+)$nth /$1 /;
$planned = $planned . $year;
my $date = Time::Piece->strptime($planned, "%d %b %Y");
$rv{qualification}->{fttc}->{date} = $date->ymd;
}
$rv{qualification}->{'first_date'} = $t->ymd;
foreach (qw/FAM1 FAM3 FAM30 FAM60 FAM90 FAM120 BUS15/) {
$rv{$_} = {
first_date => $t->ymd,
product_name => $_,
max_speed => $top
};
}
foreach (qw/BUS45 BUS90 BUS135 BUS180/) {
$rv{$_} = {
first_date => $t->ymd,
product_name => $_,
max_speed => defined $rv{qualification}->{fttc}->{down} ? $rv{qualification}->{fttc}->{down} : $top
};
}
return %rv;
}
=head2 regrade_options
$enta->regrade_options( "service-id" => "ADSL12345" );
Returns an array detailing the available regrade options on the service.
Data returned is the same as from services_available
=cut
sub regrade_options {
my ($self, %args) = @_;
my %adsl = $self->adslaccount(%args);
my $cli = $adsl{adslaccount}->{telephone};
return $self->services_available( "cli" => $cli );
}
=head2 adslchecker
$enta->adslchecker( cli => "02072221122", mac => "LSDA12345523/DF12D" );
Returns details from Enta's interface to the BT ADSL checker. See Enta docs
for details of what is returned.
cli parameter is required. mac is optional
=cut
sub adslchecker {
my ($self, %args) = @_;
$self->_check_params(\%args, ("cli|postcode"));
my $data = {
"PhoneNo" => $args{cli},
"PostCode" => $args{postcode},
"MACcode" => $args{mac},
"Version" => 4
} ;
my $response = $self->_make_request("ADSLChecker", $data);
my %results = ();
foreach (keys %{$response->{Response}->{OperationResponse}}) {
if ( ref $response->{Response}->{OperationResponse}->{$_} eq "HASH" ) {
my $a = $_;
foreach (keys %{$response->{Response}->{OperationResponse}->{$a}}) {
$results{$a}{$_} = $response->{Response}->{OperationResponse}->{$a}->{$_};
}
}
else {
$results{$_} = $response->{Response}->{OperationResponse}->{$_};
}
}
return %results;
}
=head2 username_available
$enta->username_available( username => 'abcdef' );
Returns true if the specified username is available to be used for a
customer ADSL login at Enta.
=cut
sub username_available {
my ($self, $username) = @_;
die "You must provide the username parameter" unless $username;
my $response = $self->_make_request("CheckUsernameAvailable",
{ "username" => $username } );
return undef if $response->{Response}->{OperationResponse}->{Available} eq "false";
return 1;
}
=head2 verify_mac
$enta->verify_mac( cli => "02072221111", mac => "ABCD0123456/ZY21X" );
Given a cli and MAC returns 1 if the MAC is valid.
=cut
sub verify_mac {
my ($self, %args) = @_;
$self->_check_params(\%args, qw/cli mac/);
for (qw/cli mac/) {
die "You must provide the $_ parameter" unless $args{$_};
}
my $line = $self->adslchecker(
"cli" => $args{cli},
"mac" => $args{mac}
);
return undef unless $line->{MAC}->{Valid};
return 1;
}
=head2 interleaving_status
$enta->interleaving_status( "service-id" => "ADSL12345" );
Returns the current interleaving status if available
=cut
sub interleaving_status {
my ( $self, %args ) = @_;
$self->_check_params(\%args, qw/service-id|username|telephone|ref/);
my $data = $self->_serviceid(\%args);
my $response = $self->_make_request("GetInterleaving", $data);
return $response->{Response}->{OperationResponse}->{Interleave};
}
=head2 interleaving
$enta->interleaving( "service-id" => "ADSL123456", "interleaving" => "No")
Changes the interleaving setting on the given service
=cut
sub interleaving {
my ($self, %args) = @_;
$self->_check_params(\%args, ("service-id|ref|telephone|username", "interleaving"));
die "interleaving can only be 'Yes', 'No' or 'Auto'" unless
$args{"interleaving"} =~ /(Yes|No|Auto)/;
my $data = $self->_serviceid(\%args);
$data->{"LineFeatures"}->{"Interleaving"} = $args{"interleaving"};
return $self->modifylinefeatures( %$data );
}
=head2 stabilityoption
$enta->stabilityoption( "service-id" => "ADSL123456", "option" => "Standard" );
Sets the Stability Option feature on a service
=cut
sub stabilityoption {
my ($self, %args) = @_;
$self->_check_params(\%args, ("service-id|ref|telephone|username", "option"));
die "option can only be 'Standard', 'Stable', or 'Super Stable'" unless
$args{"option"} =~ /(Standard|Stable|Super Stable)/;
my $data = $self->_serviceid(\%args);
$data->{"LineFeatures"}->{"StabilityOption"} = $args{"option"};
return $self->modifylinefeatures( %$data );
}
=head2 elevatedbestefforts
$enta->elevatedbestefforts( "service-id" => "ADSL123456", "option" => "Yes",
"fee" => "5.00" );
Enables or disables Elevated Best Efforts on the given service. If the
optional "fee" parameter is passed the monthly fee for this option is
set accordingly, otherwise it is set to the default charged by Enta.
=cut
sub elevatedbestefforts {
my ($self, %args) = @_;
$self->_check_params(\%args, ("service-id|ref|telephone|username", "option"));
die "option can only be 'Yes' or 'No'" unless
$args{option} =~ /(Yes|No)/;
my $data = $self->_serviceid(\%args);
$data->{"LineFeatures"}->{"ElevatedBestEfforts"} = $args{"option"};
$data->{"LineFeatures"}->{"ElevatedBestEffortsFee"} = $args{"fee"}
if $args{"fee"};
return $self->modifylinefeatures( %$data );
}
=head2 care_level
$enta->care_level( "service-id" -> "ADSL12345", "care-level" => "enhanced" );
Changes the care-level associated with a given service.
care-level can be set to either standard or enhanced.
Returns true is successful.
=cut
sub care_level {
my ($self, %args) = @_;
$self->_check_params( \%args );
my %data = %args;
$data{option} = 'On' if $args{"care-level"} eq 'enhanced';
$data{option} = 'Off' if $args{"care-level"} eq 'standard';
return $self->enhanced_care(%data);
}
=head2 enhanced_care
$enta-enhanced_care( "service-id" => "ADSL123456", "option" => "On",
"fee" => "15.00" );
Enables or disabled Enhanced Care on a given service. If the optional
"fee" parameter is passed the monthly fee for this option is set
accordingly, otherwise it is set to the default charged by Enta.
=cut
sub enhanced_care {
my ($self, %args) = @_;
$self->_check_params(\%args, ("service-id|ref|telephone|username", "option"));
die "option can only be 'On' or 'Off'" unless $args{option} =~ /(On|Off)/;
my $data = $self->_serviceid(\%args);
my $ec = 4 if $args{option} eq 'On';
$ec = 5 if $args{option} eq 'Off';
$data->{"LineFeatures"}->{"MaintenanceCategory"} = $ec;
$data->{"LineFeatures"}->{"MaintenanceCategoryFee"} = $args{"fee"}
if $args{"fee"};
return $self->modifylinefeatures( %$data );
}
=head2 modifylinefeatures
$enta->modifylinefeatures(
"Ref" => "ADSL123456", "Username" => "abcdef",
"Telephone" => "02071112222", "LineFeatures" => {
"Interleaving" => "No",
"StabilityOption" => "Standard",
"ElevatedBestEfforts" => "Yes",
"ElevatedBestEffortsFee" => "15.00",
"MaintenanceCategory" => "4",
"MaintenanceCategoryFee" => "25.00"
} );
Modify the Enta service reference specificed in either Ref, Username or
Telephone. Parameters are as per the Enta documentation
Returns a hash containing details of the new settings resulting from the
change(s) made - ie:
%return = { interleaving => "No" };
=cut
sub modifylinefeatures {
my ($self, %args) = @_;
$self->_check_params(\%args, ("service-id|ref|telephone|username", "LineFeatures"));
my $data = $self->_serviceid(\%args);
$data->{"LineFeatures"} = $args{"LineFeatures"};
my $response = $self->_make_request("ModifyLineFeatures", $data);
my %return = ();
foreach ( keys %{$response->{Response}->{OperationResponse}->{ADSLAccount}->{LineFeatures}} ) {
$return{lc $_} = $response->{Response}->{OperationResponse}->{ADSLAccount}->{LineFeatures}->{$_}->{NewValue};
}
return \%return;
}
=head2 order_updates_since
$enta->order_updates_since( "date" => "2009-12-01" );
Returns all the BT order updates since the given date
=cut
sub order_updates_since {
my ($self, %args) = @_;
$self->_check_params(\%args, (qw/date/));
my $from = Time::Piece->strptime($args{"date"}, "%F");
my $now = localtime;
my $d = $now - $from;
my $days = $d->days;
$days =~ s/\.\d+//;
my $date_format = "%Y-%m-%d %H:%M:%S";
$date_format = $args{dateformat} if $args{dateformat};
my @records = $self->getbtfeed( "days" => $days );
my @updates = ();
my %ref = ();
while (my $r = pop @records) {
my %a = ();
my $ref = undef;
if ( defined $ref{$r->{"telephone"}} ) {
$ref = $ref{$r->{"telephone"}};
}
else {
eval { $ref = $self->_get_ref_from_telephone($r->{"telephone"}) };
$ref = $r->{"customerref"} if ( ! $ref && $r->{"customerref"} =~ /^ADSL\d+$/);
$ref = $r->{"telephone"} if ! $ref;
}
$r->{"timestamp"} =~ /(.*) \+0\d00/;
my $t = Time::Piece->strptime($1, "%a, %d %b %Y %H:%M:%S");
$a{"date"} = $t->strftime($date_format);
$a{"order_id"} = $ref;
$a{"name"} = $r->{"ordertype"} . " " . $r->{"customerref"};
$a{"value"} = $r->{"substatus"};
$a{"value"} .= " " . $r->{"commitdate"} if $r->{"commitdate"};
push @updates, \%a;
}
return @updates;
}
=head2 getbtfeed
$enta->getbtfeed( "days" => 5 );
Returns a list of events that have occurred on all orders over the number of days specified.
Parameters:
days : The number of days up to the current date to get reports for
The return is an date/time sorted array of hashes each of which contains the following fields:
order-id
date
name
value
=cut
sub getbtfeed {
my ($self, %args) = @_;
$self->_check_params(\%args, (qw/days/));
my $response = $self->_make_request("GetBTFeed", { "Days" => $args{days} });
my @records = ();
while ( my $r = pop @{$response->{Response}->{OperationResponse}->{Records}->{Record}} ) {
my %a = ();
foreach (keys %$r) {
$a{lc $_} = $r->{$_};
}
push @records, \%a;
}
return @records;
}
=head2 update_contact
$enta->update_contact( "service-id" => "ADSL12345",
email => 'me@example.com',
telday => '02070020011',
televe => '02080020011' );
Updates the given contact details. Returns true if updated.
You can use this to change the email address, daytime telephone number
and evening telephone number of the contact for the given service.
=cut
sub update_contact {
my ( $self, %args) = @_;
$self->_check_params(\%args);
my $data = $self->_serviceid(\%args);
for (qw/Email TelDay TelEve/) {
$data->{$_} = $args{lc $_} if $args{lc $_};
}
my $response = $self->_make_request("UpdateADSLContact", $data);
return 1;
}
=head2 cease
$enta->cease( "service-id" => "ADSL12345", "crd" => "1970-01-01" );
Places a cease order to terminate the ADSL service completely.
=cut
sub cease {
my ($self, %args) = @_;
$self->_check_params(\%args);
my $data = undef;
if ( $args{'service-id'} || $args{'ref'} ) {
$data = $self->_convert_input("CeaseADSLOrder" ,\%args);
}
else {
my %adsl = $self->adslaccount(%args);
$data = { "username" => $adsl{adslaccount}->{username} };
}
my $d = Time::Piece->strptime($args{"crd"}, "%F");
$data->{"ceaseDate"} = $d->dmy('/');
my $response = $self->_make_request("CeaseADSLOrder", $data);
die "Cease order not accepted by Enta" unless $response->{Response}->{Type} eq 'Accept';
return $response->{Response}->{OperationResponse}->{OurRef};
}
=head2 request_mac
$enta->request_mac( "service-id" => 'ADSL12345');
Obtains a MAC for the given service.
Returns a hash comprising: mac, expiry-date if the MAC is available or
submits a request for the MAC which can be obtained later.
=cut
sub request_mac {
my ($self, %args) = @_;
$self->_check_params(\%args);
my %adsl = $self->adslaccount(%args);
if ( $adsl{"adslaccount"}->{"mac"} ) {
my $expires = $adsl{"adslaccount"}->{"macexpires"};
$expires =~ s/\+\d+//;
return ( "mac" => $adsl{"adslaccount"}->{"mac"},
"expiry_date" => $expires );
}
%args = ( "ref" => $adsl{adslaccount}->{ourref} );
my $data = $self->_serviceid(\%args);
my $response = $self->_make_request("RequestMAC", $data );
return ( "mac_requested" => 1 );
}
=head2 auth_log
$enta->auth_log( "service-id" => 'ADSL12345' );
Gets the most recent authentication attempt log.
=cut
sub auth_log {
my ($self, %args) = @_;
$self->_check_params(\%args);
my $data = $self->_serviceid(\%args);
my $response = $self->_make_request("LastRadiusLog", $data );
my %log = ();
my @r = ();
my $date_format = "%Y-%m-%d %H:%M:%S";
$date_format = $args{dateformat} if $args{dateformat};
my $t = Time::Piece->strptime($response->{Response}->{OperationResponse}->{DateTime}, "%d %b %Y %H:%M:%S");
$log{"auth_date"} = $t->strftime($date_format);
$log{"username"} = $response->{Response}->{OperationResponse}->{Username};
$log{"result"} = "Login OK";
$log{"ip_address"} = $response->{Response}->{OperationResponse}->{IPAddress};
push @r, \%log;
return @r;
}
=head2 max_reports
$enta->max_reports( "service-id" => "ADSL12345" );
Returns the ADSL MAX reports for connections which are based upon ADSL MAX
=cut
sub max_reports {
my ($self, %args) = @_;
$self->_check_params(\%args, ("ref|telephone|username|service-id"));
my $data = $self->_serviceid(\%args);
my $response = $self->_make_request("GetMaxReports", $data);
my %line = ();
my @rate = ();
my @profile = ();
while ( my $r = shift @{$response->{"Response"}->{"Report"}} ) {
if ( $r->{"Name"} eq "Line RateChange" ) {
while (my $rec = shift @{$r->{Record}} ) {
my %a = ();
if ( $args{dateformat} ) {
foreach ( "SyncTimestamp", "BIPUpdateTime", "LineRateTimestamp" ) {
next unless $rec->{$_};
my $d = Time::Piece->strptime($rec->{$_}, "%d/%m/%Y %H:%M:%S");
$a{lc $_} = $d->strftime($args{dateformat});
}
}
foreach ( keys %$rec ) {
$a{lc $_} = $rec->{$_};
}
push @rate, \%a;
}
}
elsif ( $r->{"Name"} eq "Service Profile" ) {
while (my $rec = shift @{$r->{Record}} ) {
my %a = ();
if ( $args{dateformat} ) {
foreach ( "SyncTimestamp", "BIPUpdateTime", "LineRateTimestamp" ) {
next unless $rec->{$_};
my $d = Time::Piece->strptime($rec->{$_}, "%d/%m/%Y %H:%M:%S");
$rec->{lc $_} = $d->strftime($args{dateformat});
}
}
foreach (keys %$rec ) {
$a{lc $_} = $rec->{$_};
}
push @profile, \%a;
}
}
}
$line{"ratechange"} = \@rate;
$line{"profile"} = \@profile;
return %line;
}
=head2 order_eventlog_history
$enta->order_eventlog_history( username => "myusername" );
Gets the provisioning history for a specified customer order.
Takes "username" as parameter.
Returns an array, each element of which details an order update.
=cut
sub order_eventlog_history { goto &getadslinstall; }
=head2 getadslinstall
$enta->getadslinstall( username => "username", dateformat => "%d %b %Y" );
Get's the provisioning history for the specified customer
Returns an array, each element of which is a hash detailing an update as
follows:
date
name
value
=cut
sub getadslinstall {
my ($self, %args) = @_;
$self->_check_params(\%args, ( 'username' ) );
my $response = $self->_make_request("GetAdslInstall", \%args);
my $dateformat = "%Y-%m-%d";
$dateformat = $args{dateformat} if $args{dateformat};
my @history = ();
while ( my $log = shift @{$response->{Response}->{OperationResponse}->{InstallReturns}->{InstallReturn}} ) {
my %a = ();
my $d = localtime($log->{DateReceived});
$a{date} = $d->strftime($dateformat);
$a{name} = "status";
$a{value} = $log->{OrderType}.' '.$log->{LineItemSubstatus};
if ( $log->{LineItemSubstatus} eq 'COMMITTED' ) {
print "Adding ".$log->{CommitDate}." to ".$a{value}."\n";
my $c = Time::Piece->strptime($log->{CommitDate}, "%d-%b-%Y");
$a{value} .= ' for '.$c->strftime($dateformat);
}
push @history, \%a;
}
return @history;
}
=head2 service_view
$enta->service_details( "service-id" => 'ADSL12345' );
Returns the ADSL service details
=cut
sub service_view { goto &adslaccount; }
=head2 service_details
$enta->service_details( "service-id" => 'ADSL12345' );
Returns the ADSL service details
=cut
sub service_details { goto &adslaccount; }
=head2 adslaccount
$enta->adslaccount( "service-id" => "ADSL12345" );
Returns details for the given service
=cut
sub adslaccount {
my ($self, %args) = @_;
$self->_check_params(\%args, ( "service-id|telephone|ref|username" ));
my $data = $self->_serviceid(\%args);
my $response = $self->_make_request("AdslAccount", $data );
my %adsl = ();
foreach (keys %{$response->{Response}->{OperationResponse}} ) {
if ( ref $response->{Response}->{OperationResponse}->{$_} eq 'HASH' ) {
my $b = $_;
foreach ( keys %{$response->{Response}->{OperationResponse}->{$b}} ) {
$adsl{lc $b}{lc $_} = $response->{Response}->{OperationResponse}->{$b}->{$_};
}
}
else {
$adsl{lc $_} = $response->{Response}->{OperationResponse}->{$_};
}
}
$adsl{service_details}->{live} = 'N';
$adsl{service_details}->{live} = 'Y' if $adsl{adslaccount}->{status} eq 'Installed';
$adsl{adslaccount}->{provisiondate} =~ /(.*) \+0\d00/;
my $activation_date = Time::Piece->strptime($1, "%a, %d %b %Y %H:%M:%S");
if ( $args{dateformat} ) {
$adsl{service_details}->{activation_date} = $activation_date->strftime($args{dateformat});
}
else {
$adsl{service_details}->{activation_date} = $activation_date->ymd;
}
return %adsl;
}
=head2 order
$enta->order(
# Customer details
forename => "Clara", surname => "Trucker", company => "ABC Ltd",
building => "123", street => "Pigeon Street", city => "Manchester",
county => "Greater Manchester", postcode => "M1 2JX",
telephone => "01614960213", email => "clare@example.com",
# Order details
clid => "01614960213", "client-ref" => "claradsl",
"prod-id" => $product, crd => $leadtime, username => "claraandhugo",
password => "skyr153", "care-level" => "standard",
realm => "surfdsl.net"
);
Submits an order for DSL to be provided to the specified phone line.
Note that all the parameters above must be supplied. CRD is the
requested delivery date in YYYY-mm-dd format; you are responsible for
computing dates after the minimum lead time. The product ID should have
been supplied to you by Enta.
Additional parameters are listed below and described in the integration
guide:
title street company mobile email fax sub-premise fixed-ip routed-ip
allocation-size hardware-product max-interleaving test-mode
inclusive-transfer
=cut
sub order {
my ($self, %args) = @_;
my @required = ( qw/title county telephone email crd
routed-ip username password linespeed topup care-level
billing-period contract-term initial-payment ongoing-payment
payment-method totl max-interleaving/ );
for (qw/ctitle cforename csurname cstreet ctown ccounty cpostcode
ctelephone cemail/) {
if ( $args{"customer-id"} eq 'New' ) {
push @required, $_;
}
else {
delete $args{$_} if $args{$_};
}
}
$self->_check_params(\%args, @required);
$args{"isdn"} = 'N';
$entatype{"CreateADSLOrder"} = "ADSLMigrationOrder" if $args{mac};
my $d = Time::Piece->strptime($args{"crd"}, "%F");
$args{"crd"} = $d->dmy("/");
my $data = $self->_convert_input("CreateADSLOrder", \%args);
my $response = $self->_make_request("CreateADSLOrder", $data);
return ( "order_id" => $response->{Response}->{OperationResponse}->{OurRef},
"service_id" => $response->{Response}->{OperationResponse}->{OurRef},
"payment_code" => $response->{Response}->{OperationResponse}->{TelephonePaymentCode} );
}
=head2 terms_and_conditions
Returns the terms-and-conditions to be presented to the user for signup
of a broadband product.
=cut
sub terms_and_conditions {
return "XXX Get terms and conditions dynamically, or just put them here";
}
=head2 product_change
$enta->product_change( "username" => "myusername", "family" => "Family",
"cap" => "30", "speed" => "8000" );
Place an order to change the specified service to the given new product.
Note that you can only use username or telephone to identify the service.
You cannot use ref or service-id
=cut
sub product_change {
my ($self, %args) = @_;
$self->_check_params(\%args, ("ref|username|telephone|service-id",
"family", "cap", "speed"));
if ( $args{"ref"} || $args{"service-id"}) {
my %adsl = $self->adslaccount(%args);
$args{"username"} = $adsl{adslaccount}->{username};
delete $args{"ref"} if $args{"ref"};
}
$args{schedule} = "FirstAvailableDate";
my $data = $self->_convert_input("ProductChange", \%args);
my $response = $self->_make_request("ProductChange", $data);
return $response->{Response}->{OperationResponse}->{ProductChange}->{Results};
}
=head2 regrade
$enta->regrade( "service-id" => "ADSL12345",
"prod-id" => "FAM30" );
Places an order to regrade the specified service to the specified prod-id.
Required parameters:
prod-id : New Enta product ID
service-id : you must provide one of service-id, ref, username or telephone
=cut
sub regrade {
my ($self, %args) = @_;
$self->_check_params(\%args);
my %adsl = $self->adslaccount(%args);
my %data = ( "username" => $adsl{adslaccount}->{username} );
my $speed = $adsl{adslaccount}->{actualbtproduct};
if ( ( $speed =~ /Premium/ && $args{"prod-id"} !~ /BUS/ ) ||
( $speed !~ /Premium/ && $args{"prod-id"} =~ /BUS/ ) ) {
die "To switch between a Family and Business product requires a manual request to Enta";
}
$speed = "24000" if $speed eq 'WBC End User Access (EUA)';
$speed = "8000" if $speed =~ /BT IPStream Max/;
$speed = "2000" if $speed =~ /BT IPStream .* 2000/;
$speed = "1000" if $speed =~ /BT IPStream .* 1000/;
$speed = "500" if $speed =~ /BT IPStream .* 500/;
$data{speed} = $speed;
if ( $args{"prod-id"} =~ /(\D+)(\d+)/ ) {
my $family = "Family";
$family = "Business" if $1 eq 'BUS';
$data{family} = $family;
$data{cap} = $2;
return $self->product_change(%data);
}
}
=head2 usage_summary
$enta->usage_summary( "service-id" => "ADSL12345", "year" => '2009', "month" => '01' );
Returns a summary of usage in the given month
=cut
sub usage_summary {
my ($self, %args) = @_;
$self->_check_params(\%args, ("service-id|ref|username|telephone"));
my $data = $self->_serviceid(\%args);
my $s = $args{year}."-".$args{month}."-1";
my $start = Time::Piece->strptime($s, "%F");
$args{"startday"} = $start->ymd;
my $e = $args{year}."-".$args{month}."-".$start->month_last_day;
my $end = Time::Piece->strptime($e, "%F");
$args{"endday"} = $end->ymd;
my @history = $self->usage_history_detail(%args);
my $downstream = 0;
my $upstream = 0;
my $peakdownstream = 0;
my $peakupstream = 0;
while ( my $h = pop @history ) {
$downstream += $h->{totaldown};
$upstream += $h->{totalup};
$peakdownstream += $h->{peakdown};
$peakupstream += $h->{peakup};
}
return (
"year" => $args{"year"},
"month" => $args{"month"},
"total_input_octets" => $downstream,
"total_output_octets" => $upstream,
"peak_input_octets" => $peakdownstream,
"peak_output_octets" => $peakupstream
);
}
=head2 usage_history
$enta->usage_history(startdatetime => '2010-01-01', enddatetime => '2010-12-01');
=cut
sub usage_history {
my ($self, %args) = @_;
$self->_check_params(\%args, (qw/startdatetime enddatetime/));
if ( $args{startdatetime} ) {
my $s = Time::Piece->strptime($args{startdatetime}, "%Y-%m-%d %H:%M:%S");
$args{startdatetime} = $s->dmy('/') . ' ' . $s->strftime("%H:%M:%S");
}
if ( $args{enddatetime} ) {
my $s = Time::Piece->strptime($args{enddatetime}, "%Y-%m-%d %H:%M:%S");
$args{enddatetime} = $s->dmy('/') . ' ' . $s->strftime("%H:%M:%S");
}
my $data = $self->_convert_input("UsageHistory", \%args);
$data->{RawDisplay} = 1;
my $response = $self->_make_request("UsageHistory", $data);
my $s = Time::Piece->strptime($response->{Response}->{OperationResponse}->{StartDateTime}, "%d %b %Y %H:%M:%S");
my $e = Time::Piece->strptime($response->{Response}->{OperationResponse}->{EndDateTime}, "%d %b %Y %H:%M:%S");
my %u = ();
if ( $args{dateformat} ) {
$u{"start_date_time"} = $s->strftime($args{dateformat});
$u{"end_date_time"} = $e->strftime($args{dateformat});
}
else {
$u{"start_date_time"} = $s->ymd.' '.$s->hms;
$u{"end_date_time"} = $e->ymd.' '.$e->hms;
}
$u{peak_download} = $response->{Response}->{OperationResponse}->{PeakDownload};
$u{peak_upload} = $response->{Response}->{OperationResponse}->{PeakUpload};
$u{download} = $response->{Response}->{OperationResponse}->{Download};
$u{upload} = $response->{Response}->{OperationResponse}->{Upload};
return %u;
}
=head2 usage_history_detail
$enta->usage_history_detail( "service-id" => "ADSL12345",
startday => '2009-12-01', endday => '2010-02-01',
dateformat => "%a, %d %m %Y");
$enta->usage_history_detail( "service-id" => "ADSL12345",
day => '2010-02-01' );
Returns usage details for each day in a period or each 10 minute period
in a day if called with day as the parameter.
Parameters:
service-id : Service identifier (or ref, username or telephone)
startday : Start date in ISO format
endday : End data in ISO format
day : Date in ISO format
dateformat : Format string per strftime. Defaults to ISO. (Optional)
Either the startday and endday parameters or the day parameter must be
passed.
Returns an array, each element of which is a hash containing usage details
for either a day or a 10 minute interval.
Data returned per a day has the following keys:
date : Date formatted for presentation ( eg Mon, 22 Feb 2010 )
totaldown : Total number of bytes downloaded
totalup : Total number of bytes uploaded
peakdown : Bytes downloaded during peak period
peakup : Bytes uploaded during peak period
Data returned per 10 minute interval for a day:
time : Time at end of measured time interval
down : bytes downloaded during interval
up : bytes uploaded during interval
=cut
sub usage_history_detail {
my ($self, %args) = @_;
my $data = $self->_serviceid(\%args);
if ( $args{"day"} ) {
my $d = Time::Piece->strptime($args{"day"}, "%F");
$data->{"day"} = $d->dmy('/');
}
elsif ( $args{"startday"} && $args{"endday"} ) {
my $s = Time::Piece->strptime($args{"startday"}, "%F");
my $e = Time::Piece->strptime($args{"endday"}, "%F");
$data->{"startday"} = $s->dmy('/');
$data->{"endday"} = $e->dmy('/');
}
else {
die "You must provide the day parameter or the startday and endday parameters";
}
my $date_format = "%Y-%m-%d";
$date_format = $args{dateformat} if $args{dateformat};
my $response = $self->_make_request("UsageHistoryDetail", $data);
my @usage = ();
if ( $args{"day"} ) {
while (my $r = shift @{$response->{ResponseType}->{Detail}->{Usage}} ) {
my %row = ();
foreach ( keys %{$r} ) {
my $key = lc $_;
$row{$key} = $r->{$_};
}
push @usage, \%row;
}
}
else {
if ( ref $response->{ResponseType}->{Day} eq 'ARRAY' ) {
while (my $r = shift @{$response->{ResponseType}->{Day}} ) {
my %row = ();
my $d = Time::Piece->strptime($r->{Date}, "%F");
$row{'date'} = $d->strftime($date_format);
$row{'totalup'} = $r->{Total}->{Up};
$row{'totaldown'} = $r->{Total}->{Down};
$row{'peakup'} = $r->{Peak}->{Up};
$row{'peakdown'} = $r->{Peak}->{Down};
push @usage, \%row;
}
}
else {
my %row = ();
my $d = Time::Piece->strptime($response->{ResponseType}->{Day}->{Date}, "%F");
$row{'date'} = $d->strftime($date_format);
$row{'totalup'} = $response->{ResponseType}->{Day}->{Total}->{Up};
$row{'totaldown'} = $response->{ResponseType}->{Day}->{Total}->{Down};
$row{'peakup'} = $response->{ResponseType}->{Day}->{Peak}->{Up};
$row{'peakdown'} = $response->{ResponseType}->{Day}->{Peak}->{Down};
push @usage, \%row;
}
}
return @usage;
}
=head2 allowance
$enta->allowance( "service-id" => "ADSL12345" );
Returns details of the customers bandwidth usage allowance including
overall allowance and any overusage (topup or payg) allowances on the
account.
=cut
sub allowance {
my ($self, %args) = @_;
$self->_check_params(\%args, ("service-id|telephone|ref|username") );
my $data = undef;
$args{'ref'} = $args{"service-id"} if $args{"service-id"};
for (qw/telephone ref username/) {
$data->{$_} = $args{$_} if $args{$_};
}
my $response = $self->_make_request("ADSLTopup", $data );
return %{$response->{Response}->{OperationResponse}};
}
=head2 session_log
$enta->session_log( "service-id" => "ADSL12345", "days" => 5 );
Returns details of recent ADSL sessions - optionally specifying the number
of days for how recent.
=cut
sub session_log {goto &connectionhistory; }
=head2 connectionhistory
$enta->connectionhistory( "service-id" => "ADSL12345", "days" => 5 );
Returns details of recent ADSL sessions - optionally specifying the number
of days for how recent.
=cut
sub connectionhistory {
my ($self, %args) = @_;
$self->_check_params(\%args, ("service-id|telephone|ref|username", "days"));
# Enta ConnectionHistory is keyed from Username only so we need to
# obtain the username if we don't have it.
my $data = undef;
if ( ! $args{"username"} ) {
my %adsl = $self->adslaccount(%args);
$data = { "username" => $adsl{adslaccount}->{username} };
}
else {
$data = $self->_serviceid(\%args);
}
$data->{days} = $args{days} if $args{days};
my $date_format = "%Y-%m-%d %H:%M:%S";
$date_format = $args{dateformat} if $args{dateformat};
my $response = $self->_make_request("ConnectionHistory", $data);
my @history = ();
if ( ref $response->{Response}->{OperationResponse}->{Connection} eq 'ARRAY' ) {
while ( my $h = pop @{$response->{Response}->{OperationResponse}->{Connection}} ) {
my %a = ();
my $start = Time::Piece->strptime($h->{"StartDateTime"}, "%d %b %Y %H:%M:%S");
my $end = Time::Piece->strptime($h->{"EndDateTime"}, "%d %b %Y %H:%M:%S");
$a{"start_time"} = $start->strftime($date_format);
$a{"stop_time"} = $end->strftime($date_format);
$a{"duration"} = $end->epoch - $start->epoch;
$a{"username"} = $h->{"Username"};
my ($download, $upload, $measure) = ();
($upload, $measure) = split(/\s/, $h->{"Input"});
$a{"upload"} = $upload * 1024*1024*1024 if $measure eq 'GB';
$a{"upload"} = $upload * 1024*1024 if $measure eq 'MB';
$a{"upload"} = $upload * 1024 if $measure eq 'KB';
($download, $measure) = split(/\s/, $h->{"Output"});
$a{"download"} = $download * 1024*1024*1024 if $measure eq 'GB';
$a{"download"} = $download * 1024*1024 if $measure eq 'MB';
$a{"download"} = $download * 1024 if $measure eq 'KB';
$a{"termination_reason"} = "Not Available";
push @history, \%a;
}
}
else {
my %a = ();
my $start = Time::Piece->strptime($response->{Response}->{OperationResponse}->{Connection}->{"StartDateTime"}, "%d %b %Y %H:%M:%S");
my $end = Time::Piece->strptime($response->{Response}->{OperationResponse}->{Connection}->{"EndDateTime"}, "%d %b %Y %H:%M:%S");
$a{"start_time"} = $start->strftime($date_format);
$a{"stop_time"} = $end->strftime($date_format);
$a{"duration"} = $end - $start;
$a{"username"} = $response->{Response}->{OperationResponse}->{Connection}->{"Username"};
my ($download, $upload, $measure) = ();
($upload, $measure) = split $response->{Response}->{OperationResponse}->{Connection}->{"Input"};
$a{"upload"} = $upload * 1024*1024*1024 if $measure eq 'GB';
$a{"upload"} = $upload * 1024*1024 if $measure eq 'MB';
$a{"upload"} = $upload * 1024 if $measure eq 'KB';
($download, $measure) = split $response->{Response}->{OperationResponse}->{Connection}->{"Output"};
$a{"download"} = $download * 1024*1024*1024 if $measure eq 'GB';
$a{"download"} = $download * 1024*1024 if $measure eq 'MB';
$a{"download"} = $download * 1024 if $measure eq 'KB';
$a{"termination_reason"} = "Not Available";
push @history, \%a;
}
return @history;
}
=head2 case_search
=cut
sub case_search {
my ( $self, %args ) = @_;
$self->_check_params(\%args, qw/ref|username|service-id/);
my $data = $self->_serviceid(\%args);
my $response = $self->_make_request("GetNotes", $data);
my @c = ();
my $date_format = "%Y-%m-%d %H:%M:%S";
$date_format = $args{dateformat} if $args{dateformat};
if ( ref $response->{Response}->{OperationResponse}->{Notes}->{Note} eq 'ARRAY' ) {
for my $c ( @{$response->{Response}->{OperationResponse}->{Notes}->{Note}} ) {
my %n = ();
$c->{TimeStamp} =~ /(.*) \+0\d00/;
my $t = Time::Piece->strptime($1, "%a, %d %b %Y %H:%M:%S");
$n{description} = $c->{Text};
$n{engineer} = 'Enta Staff';
$n{engineer} = $c->{User} if $c->{User} =~ /\@/;
$n{logged} = $t->strftime($date_format);
push @c, \%n;
}
}
else {
my %n = ();
my $c = $response->{Response}->{OperationResponse}->{Notes}->{Note};
$c->{TimeStamp} =~ /(.*) \+0\d00/;
my $t = Time::Piece->strptime($1, "%a, %d %b %Y %H:%M:%S");
$n{description} = $c->{Text};
$n{engineer} = 'Enta Staff';
$n{engineer} = $c->{User} if $c->{User} =~ /\@/;
$n{logged} = $t->strftime($date_format);
push @c, \%n;
}
return @c;
}
=head2 first_crd
$enta->first_crd();
Returns the first date an order may be placed for.
=cut
sub first_crd {
my ($self, %args) = @_;
my $t = Time::Piece->new();
$t += ONE_WEEK;
while ( is_uk_holiday($t->ymd) || ($t->wday == 1 || $t->wday == 7) ) {
$t += ONE_DAY;
}
return $t->ymd;
}
sub _get_ref_from_telephone {
my ($self, $cli) = @_;
my %adsl = $self->adslaccount( "telephone" => $cli );
return $adsl{adslaccount}->{ourref};
}
1;