2

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!

Andrew Newby
  • 4,941
  • 6
  • 40
  • 81

1 Answers1

2

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?.

brian d foy
  • 129,424
  • 31
  • 207
  • 592
  • Thanks for the reply Brian. I had a feeling it wouldn't be simple. I'm thinking I'm just going to do a replacement for "normal" characters: `tr{ÀÂÄàâäÇçÉÊÈËéêèëÏÌÎïìîÖÔÒöôòÜÛÙüûù}{AAAaaaCcEEEEeeeeIIIiiiOOOoooUUUuuu};`. This is only a backend invoice system for myself, so its not imperative they have the proper accents – Andrew Newby Oct 12 '16 at 16:11