Net::Kashflow — не работает с описаниями utf8

#perl #soap #soaplite

#perl #soap #soaplite

Вопрос:

Я знаю, что это очень старый модуль Perl (около 5 лет назад с момента последнего обновления). Я нашел это полезным для проекта, который я делаю, хотя он должен быть на Perl. Вместо того, чтобы начинать снизу вверх, я нашел это полезным для изучения основ. Я уже исправил несколько ошибок с ним, но этот я не могу понять

Рассматриваемый модуль: https://github.com/simoncozens/Net-KashFlow

Пример использования с проблемой:

 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"
});
  

Этот элемент добавляется, но значение «Description» преобразуется в:

7enzIGZvbyBiYXIgdGVzdA==

Если вы используете обычный a-z 0-9, он работает нормально (и отображается правильно). Проблема, по-видимому, заключается в том, что его кодирование в base64, а затем неправильное декодирование на другом конце. Я предполагаю, что KashFlow не собирается «исправлять» это, поэтому это действительно нужно сделать с этой целью. Я не очень знаком с модулем SOAP ::Lite (опять же, кажется, довольно старый модуль!), Но это то, что он использует.

Я думаю, что это та часть, которая касается добавления новой «строки» в счет-фактуру:

 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
  

Вы можете увидеть структуру здесь:

https://securedwebapp.com/api/service.asmx?op=InsertInvoiceLine

После изучения этого было предложено сообщить SOAP ::Lite, чтобы он не преобразовывал utf8 в base64, используя (я полагаю), что-то вроде:

Структура:

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

Так выглядит его тело> InsertInvoiceLine> InvLine> Description .. но я не уверен, как я могу сказать, чтобы он не кодировал эту конкретную строку.

Любой совет был бы очень признателен. Хотя это не является основным ограничителем показа (поскольку все данные находятся в системе), было бы намного приятнее / проще видеть имена элементов, как и ожидалось 🙂

Спасибо!

Ответ №1:

Я думаю, что это, вероятно, SOAP ::Lite решает преобразовать вещи в base64, когда он думает, что они не являются определенным подмножеством ASCII. Вы найдете эту эвристику в SOAP / Lite.pm в SOAP::Serializer :

 $self->typelookup({
       'base64Binary' =>
          [10, sub {$_[0] =~ /[^x09x0ax0dx20-x7f]/ }, 'as_base64Binary'],
       'zerostring' =>
           [12, sub { $_[0] =~ /^0d $/ }, 'as_string'],

... many other types ...
        'string' =>
           [100, sub {1}, 'as_string'],
    });
  

Это вступает в игру, когда SOAP ::Lite не знает тип объекта, потому что никто его не сообщил. Я предполагаю, что в недрах вашей программы он Description typelookup сериализуется и засовывает свои грязные рукавицы.

И отсюда вы сами по себе, потому что SOAP ::Lite — это не весело. Я бы начал с небольшого взлома SOAP ::Lite, чтобы посмотреть, что вы можете отследить. Скопируйте файл SOAP / Lite.pm куда-нибудь и поместите это местоположение в свой @INC . Таким образом, вы не будете возиться с исходным файлом.

Если вы никогда не хотите использовать base64, это может быть так же просто, как удалить эту строку в typelookup, хотя объявление Description типа было бы более правильным (но потенциально и кроличьей норой). Быстрое исправление может подождать, пока вы работаете над правильным исправлением.

Существует также размышление Perlmonk о том, как убедить SOAP ::Lite возвращать данные UTF-8 в ответах как UTF-8 ?.

Комментарии:

1. Спасибо за ответ, Брайан. У меня было ощущение, что это будет непросто. Я думаю, что я просто собираюсь заменить «обычные» символы : tr{ÀÂÄàâäÇçÉÊÈËéêèëÏÌÎïìîÖÔÒöôòÜÛÙüûù}{AAAaaaCcEEEEeeeeIIIiiiOOOoooUUUuuu}; . Это всего лишь серверная система счетов-фактур для меня, поэтому не обязательно, чтобы у них были правильные акценты