Net::Kashflow - doesn't work with utf8 descriptions - perl

I know this is a very old Perl module (5 or so years ago since the last update). I've found it useful for a project I'm doing though, that needs to be in Perl. Rather than starting from the bottom up, I've found this helpful to do the basics. I've already fixed up a few bugs with it - but this one I can't figure out
The module in question is: https://github.com/simoncozens/Net-KashFlow
An example usage with the problem is:
my $kf = Net::KashFlow->new(username => q|foo#bar.com|, password => "xxxx" );
my $i = $kf->create_invoice({
CustomerReference => "0123-1111111", CustomerID => 50108952,
CurrencyCode => "EUR"
}) || die $!;
$i->add_line({
Quantity => 1,
Description => "íéó foo bar test",
Rate => 10,
VatAmount => 4,
VatRate => 0,
CurrencyCode => "GBP"
});
This item gets added, but the "Description" value gets converted to:
7enzIGZvbyBiYXIgdGVzdA==
If you use normal a-z 0-9 it works fine (and shows correctly). The issue seems to be that its encoding into base64, and then not being decoded correctly at the other end. My guess is that KashFlow are not going to "fix" this, so it really needs to be done this end. I'm not really familiar with the SOAP::Lite module (again, a pretty old module it seems!), but that's what it uses.
This is the part I think that deals with adding a new "line" to the invoice:
InsertInvoiceLine => {
endpoint => 'https://securedwebapp.com/api/service.asmx',
soapaction => 'KashFlow/InsertInvoiceLine',
namespace => 'KashFlow',
parameters => [
SOAP::Data->new(name => 'UserName', type => 'xsd:string', attr => {}),
SOAP::Data->new(name => 'Password', type => 'xsd:string', attr => {}),
SOAP::Data->new(name => 'InvoiceID', type => 'xsd:int', attr => {}),
SOAP::Data->new(name => 'InvLine', type => 'tns:InvoiceLine', attr => {}),=> {})
], # end parameters
}, # end InsertInvoiceLine
You can see the structure here:
https://securedwebapp.com/api/service.asmx?op=InsertInvoiceLine
After researching this, it was suggested that you tell SOAP::Lite to not convert utf8 into base64, using (I assume), something like:
The structure is:
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<soap:Body>
<InsertInvoiceLine xmlns="KashFlow">
<UserName>string</UserName>
<Password>string</Password>
<InvoiceID>int</InvoiceID>
<InvLine>
<Quantity>decimal</Quantity>
<Description>string</Description>
<Rate>decimal</Rate>
<ChargeType>int</ChargeType>
<VatRate>decimal</VatRate>
<VatAmount>decimal</VatAmount>
<ProductID>int</ProductID>
<Sort>int</Sort>
<ProjID>int</ProjID>
<LineID>int</LineID>
<ValuesInCurrency>integer</ValuesInCurrency>
</InvLine>
</InsertInvoiceLine>
</soap:Body>
</soap:Envelope>
So looks like its Body > InsertInvoiceLine > InvLine > Description .. but I'm unsure how I can tell it not to encode that particular string.
Any advise would be much appreciated. While its not a major show stopper (as all the data is in the system), it would be much nicer/easier to see the item names as expected :)
Thanks!

I think this is probably SOAP::Lite deciding to convert things to base64 when it thinks they aren't a particular subset of ASCII. You'll find this heuristic in SOAP/Lite.pm in SOAP::Serializer:
$self->typelookup({
'base64Binary' =>
[10, sub {$_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/ }, 'as_base64Binary'],
'zerostring' =>
[12, sub { $_[0] =~ /^0\d+$/ }, 'as_string'],
... many other types ...
'string' =>
[100, sub {1}, 'as_string'],
});
This comes into play when SOAP::Lite doesn't know an object's type because no one has told it. I'm guessing that in the bowels of your program it's serializing Description and typelookup sticks its dirty mitts in.
And from here you are on your own because SOAP::Lite is no fun. I would start by hacking on SOAP::Lite a bit to see what you can trace. Copy the SOAP/Lite.pm file somewhere and put that location in your #INC. That way you don't mess around with the original file.
If you never want the base64, it might be as simple as deleting that line in typelookup, although declaring the Description type would be more proper (but also a rabbit's hole of work, potentially). The fast fix can stand in while you work on the right fix.
There's also the Perlmonk's meditation How to convince SOAP::Lite to return UTF-8 data in responses as UTF-8?.

Related

Get Values out of Complex Perl Hash Structures

With the following Code I can fetch Data stored in a Hash from a Database and print it out:
use Data::Dumper;
my $fdx = $s->field(); # get Hashreference from Database
print Dumper($fdx); # print out Hash
The (important part of the) Output looks like this:
$VAR1 = bless( {
'selectable' => 'true',
'_PARENT_OBJECT' => bless( {
'dirtyFlag' => 1,
'path' => undef,
'testItems' => [],
'data' => {
'TEST_10' => {
'atm_rundatahistory' => {
'1523964918' => {
'atm_prid' => {
'content' => '',
'label' => 'Problem Report IDs',
'raw' => ''
}, ...
'1523964410' => {
'atm_prid' => {
'label' => 'Problem Report IDs',
'raw' => '23361234',
'content' => '23361234'
}, ...
'Test_10' is one of hundreds of Tests, '1523964918' is one of many unix timestamps, so basically its a 32 Bit Integer, but I dont know which numbers the timestamps contain.
How do I print out / access the values for 'content' (in this case '23361234') of the most inner Hashes, for all Tests and unix timestamps, if they exist?
from here on I will describe my thoughts and what I have tried, its not necessary to read any further for this question.
I think the code I am looking for is something like:
foreach my $val($fdx{_PARENT_OBJECT}{data}{"TEST_*"}{atm_rundatahistory}{"********"}{atm_prid}{content})
print("\n$val");
However I don't know the exact Syntax, and neither do I know which placeholders to set for "Test_10", since there are many tests numbers, e.g. "...Test_132...Test_134" and the Unix timestamps can be any 32 Bit Integer, so I guess I can use start as a placeholder? e.g. "********".
After some hours of searching on the web, I haven't found a understandable tutorial on how to access values from complex Perl hash structures, I guess there are some simple syntax-rules to know and you can get any value of even very complex data structures without to much effort.
I've already read perldoc_perlreftut. If there is any other easy to understandable tutorial for these kind of problems, please recommend them to me. I don't really know how I can learn to handle such complex data structures in Perl myself.

eBay API - GerOrders not giving any results

I'm trying to figure out why my GetOrders function for the eBay API isn't working. Below are the headers I'm passing (this is in Perl):
$objHeader->push_header('X-EBAY-API-COMPATIBILITY-LEVEL' => $compatabilityLevel);
$objHeader->push_header('X-EBAY-API-DEV-NAME' => $devID);
$objHeader->push_header('X-EBAY-API-APP-NAME' => $appID);
$objHeader->push_header('X-EBAY-API-CERT-NAME' => $certID);
$objHeader->push_header('X-EBAY-API-CALL-NAME' => 'GetOrders');
$objHeader->push_header('X-EBAY-API-SITEID' => '3');
$objHeader->push_header('Content-Type' => 'text/xml');
...and the XML I'm passing is as follows:
<?xml version="1.0" encoding="utf-8" ?>
<GetOrdersRequest xmlns="urn:ebay:apis:eBLBaseComponents">
<DetailLevel>ReturnAll</DetailLevel>
<NumberOfDays>3</NumberOfDays>
<OrderRole>Seller</OrderRole><OrderStatus>Active</OrderStatus>
<RequesterCredentials><eBayAuthToken>$userToken</eBayAuthToken></RequesterCredentials>
</GetOrdersRequest>
(obviously $userToken is replaced with my actual user token)
I get a return from it:
$VAR1 = {
'xmlns' => 'urn:ebay:apis:eBLBaseComponents',
'Build' => 'E929_CORE_APIXO_17568878_R1',
'PageNumber' => '1',
'PaginationResult' => {
'TotalNumberOfPages' => '0',
'TotalNumberOfEntries' => '0'
},
'OrderArray' => {},
'Ack' => 'Success',
'HasMoreOrders' => 'false',
'Timestamp' => '2015-06-29T09:49:25.963Z',
'Version' => '929',
'ReturnedOrderCountActual' => '0',
'OrdersPerPage' => '100'
};
..but as you can see, no results. I know for a fact there are results (I've had it working with the PHP API already using the same kind of values as far as I can tell). Worst case scenario, I could create a basic PHP script to grab the results, and then pipe into the Perl script. Obviously this isn't ideal though (I would much prefer to have it all in one programming language)
Anyone got any ideas? I'm drawing a blank on it :/
Ok, I knew this would happen. 2 days of battling with this, and then as soon as I post something - I find the solution :)
The issue was that I was passing the following in the XML:
<OrderStatus>Active</OrderStatus>
It in fact needed to be:
<OrderStatus>Completed</OrderStatus>
That is now grabbing them perfectly :)

How to properly use UTF-8-encoded data from Schema inside Catalyst app?

Data defined inside Catalyst app or in templates has correct encoding and is diplayed well, but from database everything non-Latin1 is converted to ?. I suppose problem should be in model class, which is such:
use strict;
use base 'Catalyst::Model::DBIC::Schema';
__PACKAGE__->config(
schema_class => 'vhinnad::Schema::DB',
connect_info => {
dsn => 'dbi:mysql:test',
user => 'user',
password => 'password',
{
AutoCommit => 1,
RaiseError => 1,
mysql_enable_utf8 => 1,
},
'on_connect_do' => [
'SET NAMES utf8',
],
}
);
1;
I see no flaws here, but something must be wrong. I used my schema also with test scripts and data was well encoded and output was correct, but inside Catalyst app i did not get encoding right. Where may be the problem?
EDIT
For future reference i put solution here: i mixed in connect info old and new style.
Old style is like (dsn, username, passw, hashref_options, hashref_other options)
New style is (dsn => dsn, username => username, etc), so right is to use:
connect_info => {
dsn => 'dbi:mysql:test',
user => 'user',
password => 'password',
AutoCommit => 1,
RaiseError => 1,
mysql_enable_utf8 => 1,
on_connect_do => [
'SET NAMES utf8',
],
}
In a typical Catalyst setup with Catalyst::View::TT and Catalyst::Model::DBIC::Schema you'll need several things for UTF-8 to work:
add Catalyst::Plugin::Unicode::Encoding to your Catalyst app
add encoding => 'UTF-8' to your app config
add ENCODING => 'utf-8' to your TT view config
add <meta http-equiv="Content-type" content="text/html; charset=UTF-8"/> to the <head> section of your html to satisfy old IEs which don't care about the Content-Type:text/html; charset=utf-8 http header set by Catalyst::Plugin::Unicode::Encoding
make sure your text editor saves your templates in UTF-8 if they include non ASCII characters
configure your DBIC model according to DBIx::Class::Manual::Cookbook#Using Unicode
if you use Catalyst::Authentication::Store::LDAP configure your LDAP stores to return UTF-8 by adding ldap_server_options => { raw => 'dn' }
According to Catalyst::Model::DBIC::Schema#connect_info:
The old arrayref style with hashrefs for DBI then DBIx::Class options is also supported.
But you are already using the 'new' style so you shouldn't nest the dbi attributes:
connect_info => {
dsn => 'dbi:mysql:test',
user => 'user',
password => 'password',
AutoCommit => 1,
RaiseError => 1,
mysql_enable_utf8 => 1,
on_connect_do => [
'SET NAMES utf8',
],
}
This advice assumes you have fairly up to date versions of DBIC and Catalyst.
This is not necessary: on_connect_do => [ 'SET NAMES utf8' ]
Ensure the table|column charsets are UTF-8 in your DB. You can achieve things that sometimes look right even when parts are broken. The DB must be saving the character data as UTF-8 if you expect the entire chain to work.
Ensure you're using and configuring Catalyst::Plugin::Unicode::Encoding in your Catalyst app. It did have serious-ish bugs in the not too distant past so get the newest.

How can I get attributes from complex SOAP::DATA structure in SOAP::Lite?

I can't get a simple attribute value from SOAP response using SOAP::Lite.
Below the code and output of SOAP::Data. I'm trying to get value of the attribute //response/dirn/attr/uuid
my $cm = new SOAP::Lite
uri => 'http://www.cisco.com/AXL/API/1.0',
proxy => "https://10.0.0.1:8443/axl/";
my $res = $cm->getPhone(
SOAP::Data->name(phoneName => 'SEP00270D3D7A4C'),
);
for my $i ($res->valueof('//device/lines/line')) {
print Dumper($i);
#print $i->{dirn}->{attr}->{'uuid'}."\n"; # line below give me an error
}
Here the output of Data::Dumper. I actually have the requested value, but I can't get it through SOAP::Data
$VAR1 = \bless( {
'_signature' => [],
'_value' => [
bless( {
'_name' => 'dirn',
'_signature' => [],
'_value' => [
''
],
'_prefix' => '',
'_attr' => {
'uuid' => '{615C3550-1EFD-56C7-3788-2AA8725880E3}' #!!!!!!!!!!!!!!!!!!!!!!!!!!
}
}, 'SOAP::Data' ),
],
'_attr' => {}
}, 'SOAP::Data' );
I spent about several hours trying to get this attribute value. I've already thinking about using output of Data::Dumper to get the value as fast and dirty hack.
Thanks in advance
P.S.: SOAP Server is Cisco CUCM 6.1.5
$$i->value->attr->{uuid}
$i->{'_value'}[0]{'uuid'}
I think, though, I'm not sure about the [0].
I have same issue, but can not find an "quick and easy" solution to it. I developed a Perl library module to use certain vendor Web Service (WSDL). I had done many of such Web Service interfaces, but until now - all of the data was returned as XML "elements". On the contrary, this particular Web Service returns most of the data as XML elements, but also sets some - as XML attributes. I can not get values returned as attributes - since SOAP::Data methods (valueof(), body(), etc.) only return values of XML elements, but not associated attributes.
This problem is a little different from the one posted before - in that I do not know up front the XML structure that is being returned (given web service provides many different methods, and each - has different response).
So question is - how it is possible to get all of the XML data (both elements and attributes) for a generic response SOAP data
I went through the same thing recently and found the answer, refer to my question and my updated answer in the comments section.
Extract specific XML element in CDATA taken from SOAP::Lite Response Hash

Which recommended Perl modules can serialize Moose objects?

I was usually using Storable with nstore, but now I have a module that has CODE and apparently Storable doesn't like that.
I found YAML (and YAML::XS which I can't really get to work).
I also experimented a bit with MooseX::Storage without much success.
Are there other alternatives?
What would you recommend?
You can dump a coderef with Data::Dumper after setting $Data::Dumper::Deparse to a true value, but this is only intended for debugging purposes, not for serialization.
I would suggest you go back to looking at why MooseX::Storage isn't working out for you, as the authors tried really hard to present a well-abstracted and robust solution for Moose object serialization.
Update: it looks like you are running into issues serializing the _offset_sub attribute, as described in this question. Since that attribute has a builder, and its construction is fairly trivial (it just looks at the current value of another attribute), you shouldn't need to serialize it at all -- when you deserialize your object and want to use it again, the builder will be invoked the first time you call $this->offset. Consequently, you should just be able to mark it as "do not serialize":
use MooseX::Storage;
has '_offset_sub' => (
is => 'ro',
isa => 'CodeRef',
traits => [ 'DoNotSerialize' ],
lazy => 1,
builder => '_build_offset_sub',
init_arg => undef,
);
Lastly, this is somewhat orthogonal, but you can fold the offset and
_offset_sub attributes together by using the native attribute 'Code' trait:
has offset => (
is => 'bare',
isa => 'CodeRef',
traits => [ qw(Code DoNotSerialize) ],
lazy => 1,
builder => '_build_offset',
init_arg => undef,
handles => {
offset => 'execute_method',
},
);
sub _build_offset {
my ($self) = #_;
# same as previous _build_offset_sub...
}
Have a look at KiokuDB, its designed with and for Moose so it should really cover all the corners (NB. I haven't tried it myself but I keep meaning to!)
/I3az/
I believe Data::Dump::Streamer can serialize coderefs. Haven't used it myself though.