Revision 563

Date:
2016/04/12 12:53:34
Author:
ahitrov
Revision Log:
Payment plugin contenido interface. Order finder and order actions

Files:

Legend:

 
Added
 
Removed
 
Modified
  • utf8/plugins/payments/comps/contenido/payments/ajax/__json.html

     
    1 <% $json %>
    2 <%once>
    3
    4 use JSON::XS;
    5
    6 </%once>
    7 <%args>
    8
    9 $id => undef
    10
    11 </%args>
    12 <%init>
    13
    14 my %result;
    15
    16 my $json = encode_json \%result;
    17
    18 </%init>
  • utf8/plugins/payments/comps/contenido/payments/ajax/order_info.html

     
    1 <% $json %>
    2 <%once>
    3
    4 use JSON::XS;
    5 use utf8;
    6
    7 </%once>
    8 <%args>
    9
    10 $id => undef
    11
    12 </%args>
    13 <%init>
    14
    15 my %result;
    16 if ( $id && $id =~ /^\d+$/ ) {
    17 my $order = $keeper->{payments}->get_order( $id );
    18 if ( ref $order ) {
    19 $result{brief} = Encode::decode('utf-8', $m->scomp('/contenido/payments/components/block_order_brief.msn', order => $order));
    20 $result{actions} = Encode::decode('utf-8', $m->scomp('/contenido/payments/components/order_actions.msn', order_id => $order->id));
    21 }
    22 } else {
    23 $result{error} = 'Не указан или неверно указан идентификатор заказа';
    24 }
    25
    26 my $json = encode_json \%result;
    27
    28 </%init>
  • utf8/plugins/payments/comps/contenido/payments/components/block_order_brief.msn

     
    1 <div style="border:1px solid gray; padding:5px; margin:5px; color:gray; font-size:90%;">
    2 % if ( ref $order ) {
    3 <b class="prompt">Номер:</b> <% $order->id %><br>
    4 <b class="prompt">Пользователь:</b> <% $order->name %><br>
    5 <b class="prompt">Статус:</b> <% exists $status_order{$order->status} ? $status_order{$order->status} : 'неизвестный' %><br>
    6 <b class="prompt">Оплата:</b> <% exists $status_payment{$order->payment} ? $status_payment{$order->payment} : 'неизвестно' %><br>
    7 % if ( exists $order->{list} && ref $order->{list} eq 'ARRAY' && @{$order->{list}} ) {
    8 % my $i = 1;
    9 <table width="100%" border="0" cellpadding="3" cellspacing="0" class="tlistdocs">
    10 <tr>
    11 <th align="center" width="1%">#</th>
    12 <th align="center" width="97%">Позиция</th>
    13 <th align="center" width="1%">К-во</th>
    14 <th align="center" width="1%">Сумма</th>
    15 </tr>
    16 % foreach my $doc ( @{$order->{list}} ) {
    17 <tr align="center">
    18 <td nowrap><% $i++ %></td>
    19 <td align="left"><% $doc->name %></td>
    20 <td nowrap><% $doc->number %></td>
    21 <td nowrap><% sprintf("%.2f", $doc->price * $doc->number) %></td>
    22 </tr>
    23 % }
    24 </table>
    25 % }
    26 <b class="prompt">Всего:</b> <% $order->num %><br>
    27 <b class="prompt">Итог:</b> <% sprintf("%.2f", $order->sum_total) %><br>
    28 % } else {
    29 % if ( grep { $_ eq 'webshop' } split /\s+/, $state->plugins ) {
    30 <p class="err">Заказ с таким id в базе не найден.</p>
    31 % } else {
    32 <p class="rem">Плагин веб-магазина не подключен. Поиск параметров заказа невозможен.</p>
    33 % }
    34 % }
    35 </div>
    36 <%args>
    37
    38 $order => undef
    39
    40 </%args>
    41 <%init>
    42
    43 my (%status_order, %status_payment);
    44 if ( ref $order ) {
    45 my ($statord) = grep { $_->{attr} eq 'status' } $order->structure;
    46 my ($statpay) = grep { $_->{attr} eq 'payment' } $order->structure;
    47 %status_order = map { $_->[0] => $_->[1] } @{$statord->{cases}};
    48 %status_payment = map { $_->[0] => $_->[1] } @{$statpay->{cases}};
    49 }
    50
    51 </%init>
  • utf8/plugins/payments/comps/contenido/payments/components/block_transaction.msn

     
    1 <div style="border:1px solid gray; margin:10px 0; padding:5px; background:<% $bg_color %>;">
    2 <div style="width:200px; float:right;"><% $transaction->status ? 'Рабочая транзакция' : 'Тестовая транзакция' %> (<% $transaction->provider %>)</div>
    3 <% $dt->dmy('.').' '.$dt->hms %><br>
    4 <h4><% $transaction->name %></h4>
    5 <p>Сумма в валюте транзакции: <b><% sprintf("%.2f", $transaction->sum ) %> <% $transaction->currency_code %></b></p>
    6 </div>
    7 <%once>
    8 </%once>
    9 <%args>
    10
    11 $transaction => undef
    12 $operations => []
    13
    14 </%args>
    15 <%init>
    16
    17 my $bg_color = $transaction->status ? $transaction->success ? '#e8ffe8' : '#ffe8e8' : '#e8e8e8';
    18 my $dt = Contenido::DateTime->new( postgres => $transaction->mtime );
    19
    20 </%init>
  • utf8/plugins/payments/comps/contenido/payments/components/block_transaction_payture.msn

     
    1 <div style="border:1px solid gray; margin:10px 0; padding:5px; background:<% $bg_color %>;">
    2 <div style="width:200px; float:right;"><% $transaction->status ? 'Рабочая транзакция' : 'Тестовая транзакция' %> (PayTure)</div>
    3 <% $dt->dmy('.').' '.$dt->hms %><br>
    4 % if ( exists $TYPE{$transaction->name} ) {
    5 <h4><% $TYPE{$transaction->name} %></h4>
    6 % } else {
    7 <h4><% $transaction->name %></h4>
    8 % }
    9 <p>
    10 Статус операции: <% $transaction->success ? '<b style="color:green;">Успех</b>' : '<b style="color:red;">Неудача</b>' %><br>
    11 Сумма в валюте транзакции: <b><% sprintf("%.2f", $transaction->sum / 100) %> <% $transaction->currency_code %></b><br>
    12 </p>
    13 </div>
    14 <%once>
    15
    16 my %TYPE = (
    17 'Init' => 'Инициализация',
    18 'Charged' => 'Списание денежных средств',
    19 # '' => '',
    20 );
    21
    22 </%once>
    23 <%args>
    24
    25 $transaction => undef
    26
    27 </%args>
    28 <%init>
    29
    30 my $bg_color = $transaction->status ? $transaction->success ? '#e8ffe8' : '#ffe8e8' : '#e8e8e8';
    31 my $dt = Contenido::DateTime->new( postgres => $transaction->mtime );
    32
    33 </%init>
  • utf8/plugins/payments/comps/contenido/payments/components/form_order_finder.msn

     
    1 <script type="text/javascript">
    2 <!--
    3 $(document).ready(function(){
    4 $('#search-order-form').on('submit', function( ev ){
    5 ev.preventDefault();
    6 var order_id = $(this).find('input[name=order_id]').val();
    7 if ( order_id ) {
    8 $.ajax({
    9 'url' : '/contenido/payments/ajax/order_info.html',
    10 'data' : { 'id' : order_id },
    11 'dataType' : 'json',
    12 'success' : function( data ){
    13 if ( data.brief ) {
    14 $('#order-info').html( data.brief );
    15 }
    16 if ( data.actions ) {
    17 $('#order-actions').html( data.actions );
    18 }
    19 }
    20 });
    21 }
    22 });
    23 });
    24 //-->
    25 </script>
    26 <style>
    27 #form-order-finder b.prompt { display:inline-block; width:120px; }
    28 </style>
    29 <fieldset id="form-order-finder">
    30 <legend>Поиск по номеру заказа</legend>
    31 <form id="search-order-form" name="search_order" action="/contenido/payments/" method="GET" target="select">
    32 <table width="100%" border="0" cellpadding="0" cellspacing="6" class="tform">
    33 <tr><td width="98%"><input type="text" name="order_id" value="<% $order_id %>" style="width:97%;" placeholder="Введите идентификатор заказа"></td>
    34 <td width="2%" nowrap>
    35 <input type="submit" value="Искать" class="btn">
    36 </td></tr>
    37 </table>
    38 </form>
    39 <div id="order-info">
    40 % if ( $order_id ) {
    41 <& /contenido/payments/components/block_order_brief.msn, order => $order &>
    42 % }
    43 </div>
    44 </fieldset>
    45 <%args>
    46
    47 $order_id => undef
    48
    49 </%args>
    50 <%init>
    51
    52 my $order = $keeper->{payments}->get_order( $order_id );
    53
    54 </%init>
  • utf8/plugins/payments/comps/contenido/payments/components/order_actions.msn

     
    1 <fieldset>
    2 <legend>Движения по заказу</legend>
    3 % if ( @operations || @transactions ) {
    4 % if ( @operations ) {
    5 <h2>Операции</h2>
    6 <table width="100%" border="0" cellpadding="4" cellspacing="0" class="tlistdocs">
    7 <tr bgcolor="#efefef">
    8 <th>ID заказа</th>
    9 <th>Дата/время</th>
    10 <th>Результат</th>
    11 <th>Менеджер</th>
    12 </tr>
    13 % foreach my $op ( @operations ) {
    14 % my $dt = Contenido::DateTime->new( postgres => $op->ctime );
    15 % my $user = $op->uuid ? $keeper->get_user_by_id( $op->uuid ) : undef;
    16 <tr>
    17 <td><% $op->id %></td>
    18 <td><% $dt->ymd('-').' '.$dt->hms %></td>
    19 <td><% $opnames{$op->name} %></td>
    20 <td>
    21 % if ( ref $user ) {
    22 % $m->out($user->name);
    23 % } elsif ( $op->uuid ) {
    24 Неопознанный (id=<% $op->uuid %>)
    25 % }
    26 </td>
    27 </tr>
    28 % }
    29 </table>
    30 <p class="rem">Операция - действие пользователя или менеджера по отношению к заказу.</p>
    31 % }
    32 % if ( @transactions ) {
    33 <h2>Транзакции</h2>
    34 % foreach my $tr ( @transactions ) {
    35 % if ( $m->comp_exists( "/contenido/payments/components/block_transaction_".$tr->provider.".msn" ) ) {
    36 % $m->comp( "/contenido/payments/components/block_transaction_".$tr->provider.".msn", transaction => $tr );
    37 % } else {
    38 % $m->comp( "/contenido/payments/components/block_transaction.msn", transaction => $tr );
    39 % }
    40 % }
    41 <p class="rem">Транзакция - результат взаимодействия платежной системы и веб-магазина по отношению к заказу.</p>
    42 % }
    43 % } elsif ( $order_id ) {
    44 <p class="rem">По данному номеру заказа ничего не найдено.</p>
    45 % }
    46 </fieldset>
    47 <%once>
    48
    49
    50
    51 </%once>
    52 <%args>
    53
    54 $order_id => undef
    55
    56 </%args>
    57 <%init>
    58
    59 my ( @operations, @transactions );
    60
    61 if ( $order_id && $order_id =~ /^\d+$/ ) {
    62 @operations = $keeper->get_documents(
    63 class => 'payments::Operation',
    64 order_id => $order_id,
    65 order_by => 'ctime',
    66 );
    67 @transactions = $keeper->get_documents(
    68 class => 'payments::Transaction',
    69 order_id => $order_id,
    70 order_by => 'ctime',
    71 );
    72 }
    73 my ($prop) = grep { $_->{attr} eq 'name' } payments::Operation->new->structure;
    74 my %opnames = map { $_->[0] => $_->[1] } @{$prop->{cases}};
    75
    76 </%init>
  • utf8/plugins/payments/comps/contenido/payments/index.html

     
    1 1 <& "/contenido/components/header.msn" &>
    2 2 <& "/contenido/components/naviline.msn" &>
    3 3
    4 <p>PLugin [payments]</p>
    4 <script type="text/javascript">
    5 <!--
    6 var nOrderId = <% $order_id || 0 %>;
    5 7
    8 //-->
    9 </script>
    10
    11 <table width="100%" cellspacing="0" cellpadding="0" border="0">
    12 <tr valign="top">
    13 <td width="35%">
    14 <& /contenido/payments/components/form_order_finder.msn, order_id => $order_id &>
    15 </td>
    16 <td width="2%" nowrap>&nbsp;</td>
    17 <td width="63%">
    18 <div id="order-actions">
    19 % if ( $order_id ) {
    20 <& /contenido/payments/components/order_actions.msn, order_id => $order_id &>
    21 % }
    22 </div>
    23 </td>
    24 </tr>
    25 </table>
    26
    6 27 </body>
    7 28 </html>
    29 <%args>
    30
    31 $order_id => undef
    32
    33 </%args>
    34 <%init>
    35
    36 $order_id = undef unless $order_id && $order_id =~ /^\d+$/;
    37
    38 </%init>
  • utf8/plugins/payments/comps/www/payment.backend/payture_pay.html

     
    43 43 $transaction->success( $Success eq 'True' ? 1 : 0 );
    44 44 $transaction->store;
    45 45
    46 if ( $keeper->can('_payture_handler') ) {
    46 if ( $transaction->success && $keeper->can('_payture_handler') ) {
    47 47 $keeper->_payture_handler( $transaction );
    48 48 }
    49 49 }
  • utf8/plugins/payments/lib/payments/Keeper.pm

     
    49 49 return undef;
    50 50 }
    51 51
    52 sub get_order {
    53 my $self = shift;
    54 my $order_id = shift;
    55 return undef unless $order_id;
    52 56
    57 if ( grep { $_ eq 'webshop' } split(/\s+/, $state->plugins) ) {
    58 return $keeper->{webshop}->get_orders( id => $order_id, list => 1 );
    59 }
    60 }
    61
    53 62 1;
  • utf8/plugins/payments/lib/payments/Operation.pm

     
    6 6 return (
    7 7 { 'attr' => 'name', 'type' => 'status', 'rusname' => 'Тип операции',
    8 8 'cases' => [
    9 ['create', 'Заказ создан'],
    10 ['suspend', 'Заказ заморожен'],
    11 ['reform', 'Заказ изменен'],
    12 ['append', 'Доплата по заказу'],
    13 ['cancel', 'Заказ отменен'],
    9 ['create', 'создан'],
    10 ['suspend', 'заморожен'],
    11 ['reform', 'изменен'],
    12 ['append', 'доплата'],
    13 ['cancel', 'отменен'],
    14 ['close', 'закрыт'],
    14 15 ],
    15 16 },
    16 17 )
  • utf8/plugins/payments/lib/payments/SQL/OperationsTable.pm

     
    58 58 'db_type' => 'integer',
    59 59 'db_opts' => "default 0",
    60 60 },
    61 {
    62 'attr' => 'uuid',
    63 'type' => 'integer',
    64 'rusname' => 'ID менеджера',
    65 'db_field' => 'uuid',
    66 'db_type' => 'integer',
    67 },
    61 68 { # ID заказа
    62 69 'attr' => 'order_id',
    63 70 'type' => 'integer',
  • utf8/plugins/payments/lib/payments/State.pm.proto

     
    12 12 bless $self, $class;
    13 13
    14 14 # configured
    15 $self->{debug} = (lc('') eq 'yes');
    16 $self->{project} = '';
    15 $self->{project} = '@PROJECT@';
    16 $self->{debug} = (lc('@DEBUG@') eq 'yes');
    17 $self->{contenido_notab} = 0;
    18 $self->{tab_name} = 'Онлайн-оплата';
    19 $self->{project_name} = '@PROJECT_NAME@';
    20 $self->{default_expire} = '@DEFAULT_EXPIRE@' || 300;
    21 $self->{default_object_expire} = '@DEFAULT_OBJECT_EXPIRE@' || 600;
    17 22
    18 23 # зашитая конфигурация плагина
    19 24 $self->{db_type} = 'none'; ### For REAL database use 'remote'
     
    27 32 $self->{cascade} = 1;
    28 33 $self->{db_prepare} = 0;
    29 34
    30 $self->{memcached_enable} = lc( '' ) eq 'yes' ? 1 : 0;
    31 $self->{memcached_enable_compress} = 1;
    32 $self->{memcached_backend} = '';
    33 $self->{memcached_servers} = [qw()];
    34 $self->{memcached_busy_lock} = 60;
    35 $self->{memcached_delayed} = lc('') eq 'yes' ? 1 : 0;
    35 $self->{memcached_enable} = lc( '@MEMCACHED_ENABLE@' ) eq 'yes' ? 1 : 0;
    36 $self->{memcached_backend} = '@MEMCACHED_BACKEND@';
    37 $self->{memcached_select_timeout} = '@MEMCACHED_SELECT_TIMEOUT@' || 0.2;
    38 $self->{memcached_servers} = [qw(@MEMCACHED_SERVERS@)];
    39 $self->{memcached_enable_compress} = lc( '@MEMCACHED_ENABLE_COMPRESS@' ) eq 'yes' ? 1 : 0;
    40 $self->{memcached_delayed} = lc('@MEMCACHED_DELAYED@') eq 'yes' ? 1 : 0;
    41 $self->{memcached_set_mode} = lc('@MEMCACHED_SET_MODE@') eq 'add' ? 'add' : 'set';
    42 $self->{memcached_busy_lock} = 60;
    43 $self->{memcached_namespace} = lc( $self->{'project'} ).'|plugin_payments|';
    36 44
    37 45 $self->{serialize_with} = 'json'; ### or 'dumper'
    38 46
     
    92 100 $self->{attributes}->{$_} = 'SCALAR' for qw(
    93 101 debug
    94 102 project
    103 tab_name
    95 104
    96 105 db_type
    97 106 db_keepalive
     
    106 115 db_client_encoding
    107 116
    108 117 memcached_enable
    118 memcached_servers
    119 memcached_select_timeout
    120 memcached_backend
    109 121 memcached_enable_compress
    110 memcached_backend
    111 memcached_servers
    122 memcached_set_mode
    123 memcached_object_expire
    112 124 memcached_busy_lock
    113 125 memcached_delayed
    126 memcached_namespace
    114 127
    115 128 binary_directory
    116 129 data_directory
  • utf8/plugins/payments/sql/TOAST/operations.563.sql

     
    1 alter table payments_operations add column uuid integer;
    2 CREATE INDEX payments_operations_uuid ON payments_operations USING btree (uuid) where uuid is not null;
  • utf8/plugins/payments/sql/TOAST/operations.sql

     
    8 8 name text,
    9 9 order_id integer not null,
    10 10 uid integer not null,
    11 uuid integer,
    11 12 sum float,
    12 13 data text
    13 14 );

Небольшая справка по веткам

cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.

koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.

utf8 – актуальная ветка, заточенная под UTF-8.

Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.